| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | 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 |
| | | { |
| | |
| | | } |
| | | |
| | | @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)) |
| | |
| | | } |
| | | |
| | | @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)) |