package com.ruoyi.device.bts;
|
|
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 java.time.Instant;
|
import org.junit.jupiter.api.Test;
|
import com.ruoyi.device.model.DeviceWorkStatus;
|
import com.ruoyi.device.simulator.BtsSimulatorStateStore.BtsPlaybackState;
|
import com.ruoyi.device.simulator.InMemoryBtsSimulatorStateStore;
|
|
/** Ticket21:检测柜 record、step、cycle 生命周期和播放控制合同。 */
|
class BtsDevelopmentSimulatorRecordStepCycleTest
|
{
|
@Test
|
void recordsUseMinuteDeviceTimeAndActualStepCycleIdentity() throws Exception
|
{
|
Instant start = Instant.parse("2026-08-31T00:00:00Z");
|
try (BtsDevelopmentSimulator simulator = new BtsDevelopmentSimulator(0,
|
new InMemoryBtsSimulatorStateStore()))
|
{
|
simulator.updateChannel(1, 1, true, DeviceWorkStatus.WORKING);
|
simulator.advanceBts(start);
|
simulator.advanceBts(start.plusSeconds(5 * 60L));
|
|
var records = simulator.btsRecords(1, 1);
|
assertTrue(records.size() >= 6);
|
assertEquals(1L, records.get(0).sequenceId());
|
assertEquals(60L, records.get(1).deviceTime().getEpochSecond() - records.get(0).deviceTime().getEpochSecond());
|
assertEquals(1, records.get(0).cycleNo());
|
assertTrue(simulator.btsSteps(1, 1).stream().anyMatch(step -> step.stepNo() == 1));
|
var cycle = simulator.btsCycles(1, 1).stream().filter(item -> item.cycleNo() == 1).findFirst().orElseThrow();
|
assertTrue(cycle.chargeCapacityAh() >= 0d);
|
assertTrue(cycle.dischargeCapacityAh() >= 0d);
|
assertEquals(cycle.chargeCapacityAh() > 0d ? cycle.dischargeCapacityAh() / cycle.chargeCapacityAh() * 100d : 0d,
|
cycle.efficiency(), 0.000001d);
|
}
|
}
|
|
@Test
|
void testSnapshotExposesPlanRowsEvenBeforeRecordsAreProduced() throws Exception
|
{
|
try (BtsDevelopmentSimulator simulator = new BtsDevelopmentSimulator(0,
|
new InMemoryBtsSimulatorStateStore()))
|
{
|
var snapshot = simulator.btsTest(1, 1);
|
assertTrue(snapshot.plannedCycleCount() > 0);
|
assertTrue(snapshot.rows().stream().anyMatch(row -> "STEP".equals(row.rowType())));
|
assertTrue(snapshot.rows().stream().anyMatch(row -> "CYCLE".equals(row.rowType())));
|
assertTrue(snapshot.rows().stream().anyMatch(row -> "END".equals(row.rowType())));
|
assertEquals(0, simulator.btsRecords(1, 1).size());
|
}
|
}
|
|
@Test
|
void testSnapshotKeepsCurrentStepVisibleWhenPlaybackEntersNextCycle() throws Exception
|
{
|
InMemoryBtsSimulatorStateStore store = new InMemoryBtsSimulatorStateStore();
|
try (BtsDevelopmentSimulator simulator = new BtsDevelopmentSimulator(0, store))
|
{
|
simulator.updateChannel(1, 1, true, DeviceWorkStatus.WORKING);
|
simulator.nextBtsCycle(1, 1);
|
var snapshot = simulator.btsTest(1, 1);
|
assertTrue(snapshot.rows().stream().anyMatch(row -> "STEP".equals(row.rowType()) && "进行中".equals(row.executionStatus())));
|
assertTrue(snapshot.rows().stream().anyMatch(row -> "STEP".equals(row.rowType()) && "待执行".equals(row.executionStatus())));
|
}
|
}
|
|
@Test
|
void playbackSpeedPauseResumeAndRestartAreIndependentOfDeviceStatus() throws Exception
|
{
|
Instant start = Instant.parse("2026-08-31T00:00:00Z");
|
InMemoryBtsSimulatorStateStore store = new InMemoryBtsSimulatorStateStore();
|
try (BtsDevelopmentSimulator simulator = new BtsDevelopmentSimulator(0, store))
|
{
|
simulator.updateChannel(1, 1, true, DeviceWorkStatus.WORKING);
|
simulator.setBtsSpeed(1, 1, 600);
|
simulator.advanceBts(start);
|
simulator.pauseBts(1, 1);
|
int pausedCount = simulator.btsRecords(1, 1).size();
|
simulator.advanceBts(start.plusSeconds(600));
|
assertEquals(pausedCount, simulator.btsRecords(1, 1).size());
|
assertFalse(simulator.btsPlayback(1, 1).playback().playing());
|
}
|
try (BtsDevelopmentSimulator restored = new BtsDevelopmentSimulator(0, store))
|
{
|
BtsPlaybackState playback = restored.btsPlayback(1, 1).playback();
|
assertEquals(600, playback.speedMultiplier());
|
assertFalse(playback.playing());
|
restored.resumeBts(1, 1);
|
assertTrue(restored.btsPlayback(1, 1).playback().playing());
|
}
|
}
|
|
@Test
|
void nextCycleAndResetDoNotSendDeviceControlAndNaturalFinishStopsPlayback() throws Exception
|
{
|
InMemoryBtsSimulatorStateStore store = new InMemoryBtsSimulatorStateStore();
|
try (BtsDevelopmentSimulator simulator = new BtsDevelopmentSimulator(0, store))
|
{
|
simulator.updateChannel(1, 1, true, DeviceWorkStatus.WORKING);
|
simulator.nextBtsCycle(1, 1);
|
assertEquals(2, simulator.btsPlayback(1, 1).playback().cycleNo());
|
long firstCycleTwoRecord = BtsExcelFixture.records().stream()
|
.filter(record -> record.cycleNo() == 2).findFirst().orElseThrow().sequenceId();
|
assertEquals(firstCycleTwoRecord, simulator.btsPlayback(1, 1).playback().nextSequence());
|
Instant jumpedAt = simulator.btsPlayback(1, 1).playback().wallClockAt();
|
simulator.advanceBts(jumpedAt.plusSeconds(60));
|
assertEquals(2, simulator.btsRecords(1, 1).get(0).cycleNo());
|
simulator.setBtsSpeed(1, 1, 600);
|
Instant wallClock = simulator.btsPlayback(1, 1).playback().wallClockAt();
|
long durationMillis = BtsExcelFixture.record(BtsExcelFixture.recordCount()).offsetSeconds() * 1000L;
|
simulator.advanceBts(wallClock.plusMillis(durationMillis / 600L + 1000L));
|
assertTrue(simulator.btsPlayback(1, 1).playback().naturallyFinished());
|
simulator.resetBts(1, 1);
|
assertEquals(0, simulator.btsRecords(1, 1).size());
|
assertEquals(1, simulator.btsPlayback(1, 1).playback().cycleNo());
|
}
|
try (BtsDevelopmentSimulator restored = new BtsDevelopmentSimulator(0, store))
|
{
|
assertEquals(0, restored.btsRecords(1, 1).size());
|
assertEquals(1, restored.btsPlayback(1, 1).playback().cycleNo());
|
}
|
}
|
|
@Test
|
void playbackFollowsExcelFixtureThroughAllCyclesAndRecords() throws Exception
|
{
|
Instant start = Instant.parse("2026-08-31T00:00:00Z");
|
try (BtsDevelopmentSimulator simulator = new BtsDevelopmentSimulator(0,
|
new InMemoryBtsSimulatorStateStore()))
|
{
|
simulator.updateChannel(1, 1, true, DeviceWorkStatus.WORKING);
|
simulator.advanceBts(start);
|
simulator.setBtsSpeed(1, 1, 600);
|
Instant wallClock = simulator.btsPlayback(1, 1).playback().wallClockAt();
|
long durationMillis = BtsExcelFixture.record(BtsExcelFixture.recordCount()).offsetSeconds() * 1000L;
|
simulator.advanceBts(wallClock.plusMillis(durationMillis / 600L + 1000L));
|
|
var records = simulator.btsRecords(1, 1);
|
assertEquals(7605, records.size());
|
assertEquals(7605L, records.get(records.size() - 1).sequenceId());
|
assertEquals(33, records.get(records.size() - 1).cycleNo());
|
assertEquals(33, simulator.btsCycles(1, 1).size());
|
assertEquals(129, simulator.btsSteps(1, 1).size());
|
assertTrue(simulator.btsPlayback(1, 1).playback().naturallyFinished());
|
}
|
}
|
}
|