| | |
| | | package com.ruoyi.system.service.impl; |
| | | |
| | | import static org.junit.jupiter.api.Assertions.assertFalse; |
| | | import static org.junit.jupiter.api.Assertions.assertEquals; |
| | | import static org.junit.jupiter.api.Assertions.assertTrue; |
| | | import static org.mockito.ArgumentMatchers.any; |
| | | import static org.mockito.ArgumentMatchers.anyInt; |
| | | import static org.mockito.Mockito.mock; |
| | | import static org.mockito.Mockito.when; |
| | | |
| | | import java.io.IOException; |
| | | import java.math.BigDecimal; |
| | | import java.time.Duration; |
| | | import java.time.Instant; |
| | | import java.util.List; |
| | |
| | | import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; |
| | | import com.ruoyi.device.bts.BtsDevelopmentSimulator; |
| | | import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore; |
| | | import com.ruoyi.device.model.ChannelIdentity; |
| | | import com.ruoyi.device.model.DeviceWorkStatus; |
| | | import com.ruoyi.device.model.RealtimeSnapshot; |
| | | import com.ruoyi.system.domain.TTest; |
| | | import com.ruoyi.system.domain.TTestBattery; |
| | | import com.ruoyi.system.domain.TTestChannelBinding; |
| | | import com.ruoyi.system.service.ITTestService; |
| | | import com.ruoyi.system.service.ITestLiveService.LiveState; |
| | | |
| | | /** 实时流客户端断连时应结束连接而不触发全局异常处理。 */ |
| | | class TTestLiveServiceImplTest |
| | | { |
| | | @Test |
| | | void notStartedShouldNotExposePreTestDeviceSnapshot() |
| | | { |
| | | Instant now = Instant.parse("2026-09-02T06:00:00Z"); |
| | | TTest test = test("NOT_STARTED"); |
| | | TTestLiveServiceImpl service = liveService(test, now); |
| | | |
| | | LiveState state = service.current(10L); |
| | | |
| | | assertTrue(state.sources().stream().allMatch(source -> source.latestSnapshot().isEmpty())); |
| | | } |
| | | |
| | | @Test |
| | | void receivingShouldExposeBtsCoreMeasurements() |
| | | { |
| | | Instant now = Instant.parse("2026-09-02T06:00:00Z"); |
| | | TTest test = test("RECEIVING"); |
| | | TTestLiveServiceImpl service = liveService(test, now); |
| | | |
| | | LiveState state = service.current(10L); |
| | | var snapshot = state.sources().stream().filter(source -> "CABINET_CHANNEL".equals(source.sourceType())) |
| | | .findFirst().orElseThrow().latestSnapshot(); |
| | | |
| | | assertEquals(new BigDecimal("3.700"), snapshot.get("voltageV")); |
| | | assertEquals(new BigDecimal("1.200"), snapshot.get("currentA")); |
| | | assertEquals(new BigDecimal("2.500"), snapshot.get("capacityAh")); |
| | | } |
| | | |
| | | private static TTest test(String receptionStatus) |
| | | { |
| | | TTest test = new TTest(); |
| | | test.setTestId(10L); |
| | | test.setTestStatus("RECEIVING".equals(receptionStatus) ? "RUNNING" : "WAITING"); |
| | | test.setReceptionStatus(receptionStatus); |
| | | TTestBattery battery = new TTestBattery(); |
| | | battery.setBatteryNo("B-01"); |
| | | TTestChannelBinding binding = new TTestChannelBinding(); |
| | | binding.setChannelId(1L); |
| | | binding.setAdapterCode("dev-sim"); |
| | | binding.setDevtype(1); |
| | | binding.setDevid(1); |
| | | binding.setSubdevid(0); |
| | | binding.setChlid(1); |
| | | battery.setBinding(binding); |
| | | test.setBatteries(List.of(battery)); |
| | | return test; |
| | | } |
| | | |
| | | private static TTestLiveServiceImpl liveService(TTest test, Instant now) |
| | | { |
| | | DeviceDiscoveryCandidateStore candidates = mock(DeviceDiscoveryCandidateStore.class); |
| | | BtsDevelopmentSimulator simulator = mock(BtsDevelopmentSimulator.class); |
| | | ITTestService tests = mock(ITTestService.class); |
| | | when(tests.selectTestById(10L)).thenReturn(test); |
| | | ChannelIdentity identity = new ChannelIdentity("dev-sim", 1, 1, 0, 1); |
| | | RealtimeSnapshot snapshot = new RealtimeSnapshot(identity, DeviceWorkStatus.WORKING, 1, 1, "cc", null, |
| | | new BigDecimal("1.200"), new BigDecimal("3.700"), new BigDecimal("2.500"), |
| | | new BigDecimal("9.250"), 12L, 12L, "0", now, |
| | | java.util.Map.of()); |
| | | DeviceDiscoveryCandidateStore.ChannelCandidate channel = new DeviceDiscoveryCandidateStore.ChannelCandidate( |
| | | identity, true, DeviceWorkStatus.WORKING, now, snapshot); |
| | | DeviceDiscoveryCandidateStore.CabinetCandidate cabinet = new DeviceDiscoveryCandidateStore.CabinetCandidate( |
| | | "dev-sim", 1L, "dev-sim", 1, 1, "127.0.0.2", "mac", "cabinet", "vendor", "model", |
| | | List.of(channel), now, now.plusSeconds(60)); |
| | | when(candidates.snapshot(any(Instant.class))).thenReturn( |
| | | new DeviceDiscoveryCandidateStore.CandidateSnapshot(List.of(cabinet), List.of())); |
| | | var plan = new BtsDevelopmentSimulator.BtsTestSnapshot(1, 1, 1, List.of()); |
| | | when(simulator.btsTest(anyInt(), anyInt())).thenReturn(plan); |
| | | when(simulator.btsTest(anyInt(), anyInt(), anyInt())).thenReturn(plan); |
| | | return new CurrentLiveService(tests, candidates, simulator); |
| | | } |
| | | |
| | | @Test |
| | | void initialWriteFailureShouldCompleteStreamWithoutErrorDispatch() |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | private static final class CurrentLiveService extends TTestLiveServiceImpl |
| | | { |
| | | private CurrentLiveService(ITTestService tests, DeviceDiscoveryCandidateStore candidates, |
| | | BtsDevelopmentSimulator simulator) |
| | | { |
| | | super(tests, candidates, simulator); |
| | | } |
| | | } |
| | | |
| | | private static final class RecordingEmitter extends SseEmitter |
| | | { |
| | | private final int successfulWrites; |