| | |
| | | import com.battery.business.service.ITTestService; |
| | | import com.battery.business.service.ITestLiveService.LiveState; |
| | | |
| | | /** 实时流客户端断连时应结束连接而不触发全局异常处理。 */ |
| | | /** 验证当前测量、实时提醒与历史待办独立,以及实时流断连后的资源清理。 */ |
| | | class TTestLiveServiceImplTest |
| | | { |
| | | @Test |
| | | void thresholdWarningsRespectDeviceTimeAndReceptionBoundary() |
| | | { |
| | | Instant now = Instant.parse("2026-09-05T12:00:00Z"); |
| | | TTest test = test("RECEIVING"); |
| | | test.setStartedAtUtc(java.util.Date.from(now)); |
| | | test.setReceptionBoundaryAtUtc(java.util.Date.from(now)); |
| | | var rule = new com.battery.business.domain.TTestWarningThreshold(); |
| | | rule.setThresholdId(11L); rule.setMetricCode("VOLTAGE"); rule.setMaxValue(new BigDecimal("3")); |
| | | test.setThresholds(List.of(rule)); |
| | | assertTrue(liveService(test, now, now.minusSeconds(1)).current(10L).exceptions().isEmpty()); |
| | | assertEquals(1, liveService(test, now, now).current(10L).exceptions().size()); |
| | | test.setReceptionBoundaryAtUtc(java.util.Date.from(now.plusSeconds(1))); |
| | | assertTrue(liveService(test, now, now).current(10L).exceptions().isEmpty()); |
| | | |
| | | var battery = test.getBatteries().get(0); battery.setCollectorId(7L); battery.setBinding(null); |
| | | var binding = new com.battery.business.domain.TTestCollectorChannel(); |
| | | binding.setChannelCode("S-01"); binding.setMeasurementCode("PRIMARY_TEMPERATURE"); |
| | | battery.setCollectorChannels(List.of(binding)); |
| | | rule.setMetricCode("TEMPERATURE"); rule.setMaxValue(new BigDecimal("33")); |
| | | var tests = mock(ITTestService.class); when(tests.selectTestById(10L)).thenReturn(test); |
| | | var mapper = mock(TTestMapper.class); when(mapper.selectCollectorCode(7L)).thenReturn("collector-7"); |
| | | var adapter = mock(TestDataObservationAdapter.class); |
| | | var service = new TTestLiveServiceImpl(tests, |
| | | new com.battery.device.api.discovery.InMemoryDeviceDiscoveryCandidateStore(), adapter, mapper); |
| | | test.setReceptionBoundaryAtUtc(java.util.Date.from(now)); |
| | | for (Instant deviceTime : List.of(now.minusSeconds(1), now)) { |
| | | var measurement = new TestDataObservationAdapter.CollectorMeasurement("S-01", 1L, deviceTime, deviceTime.toString(), |
| | | now, "TEMPERATURE", new BigDecimal("38"), "℃"); |
| | | when(adapter.latestCollector(org.mockito.ArgumentMatchers.nullable(String.class), org.mockito.ArgumentMatchers.eq("collector-7"))).thenReturn(new TestDataObservationAdapter.CollectorRealtime( |
| | | "collector-7", true, 1000, List.of(measurement), null)); |
| | | assertEquals(deviceTime.equals(now) ? 1 : 0, service.current(10L).exceptions().size()); |
| | | } |
| | | test.setReceptionBoundaryAtUtc(java.util.Date.from(now.plusSeconds(1))); |
| | | assertTrue(service.current(10L).exceptions().isEmpty()); |
| | | } |
| | | |
| | | @Test |
| | | void currentTemperatureAlarmIsIndependentOfHistoricalTodoHandling() throws Exception |
| | | { |
| | | try (var simulator = new com.battery.device.simulator.BtsDevelopmentSimulator(0)) { |
| | | TTest test = test("RECEIVING"); |
| | | var battery = test.getBatteries().get(0); battery.setCollectorId(7L); |
| | | var primary = new com.battery.business.domain.TTestCollectorChannel(); |
| | | primary.setChannelCode("S-01"); primary.setMeasurementCode("PRIMARY_TEMPERATURE"); |
| | | var secondary = new com.battery.business.domain.TTestCollectorChannel(); |
| | | secondary.setChannelCode("S-03"); secondary.setMeasurementCode("SECONDARY_TEMPERATURE_2"); |
| | | battery.setCollectorChannels(List.of(primary, secondary)); |
| | | var rule = new com.battery.business.domain.TTestWarningThreshold(); |
| | | rule.setThresholdId(11L); rule.setMetricCode("TEMPERATURE"); |
| | | rule.setMinValue(new BigDecimal("8")); rule.setMaxValue(new BigDecimal("33")); |
| | | test.setThresholds(List.of(rule)); |
| | | var tests = mock(ITTestService.class); when(tests.selectTestById(10L)).thenReturn(test); |
| | | var mapper = mock(TTestMapper.class); when(mapper.selectCollectorCode(7L)).thenReturn("dev-sim-collector-1"); |
| | | var service = new TTestLiveServiceImpl(tests, |
| | | new com.battery.device.api.discovery.InMemoryDeviceDiscoveryCandidateStore(), simulator, mapper); |
| | | simulator.configureCollectorChannel(1, "S-01", List.of( |
| | | new com.battery.device.simulator.BtsSimulatorStateStore.CollectorMetricState("temperature", new BigDecimal("38"), "℃"))); |
| | | var alarms = service.current(10L).exceptions().stream().filter(item -> "THRESHOLD".equals(item.get("exceptionType"))).toList(); |
| | | assertEquals(1, alarms.size()); |
| | | assertEquals(new BigDecimal("38"), alarms.get(0).get("value")); |
| | | assertEquals("7:S-01", alarms.get(0).get("sourceIdentity")); |
| | | assertFalse(alarms.get(0).containsKey("exceptionId")); |
| | | |
| | | var history = new TTestWarningException(); history.setExceptionStatus("OPEN"); |
| | | history.setExceptionType("THRESHOLD"); history.setMetricCode("temperature"); |
| | | history.setAbnormalValue(new BigDecimal("38")); |
| | | when(mapper.selectWarningExceptions(10L, "OPEN")).thenReturn(List.of(history)); |
| | | simulator.configureCollectorChannel(1, "S-01", List.of( |
| | | new com.battery.device.simulator.BtsSimulatorStateStore.CollectorMetricState("temperature", new BigDecimal("25"), "℃"))); |
| | | assertTrue(service.current(10L).exceptions().stream().noneMatch(item -> "THRESHOLD".equals(item.get("exceptionType")))); |
| | | assertEquals("OPEN", history.getExceptionStatus()); |
| | | } |
| | | } |
| | | |
| | | @Test |
| | | void consoleReadsConfiguredSimulatorPlanAtCurrentChannelPosition() throws Exception |
| | | { |
| | |
| | | private static TTestLiveServiceImpl liveService(TTest test, Instant now, boolean online, |
| | | DeviceWorkStatus workStatus, TTestMapper mapper) |
| | | { |
| | | return liveService(test, now, online, workStatus, mapper, now); |
| | | } |
| | | |
| | | private static TTestLiveServiceImpl liveService(TTest test, Instant now, Instant deviceTime) |
| | | { |
| | | return liveService(test, now, true, DeviceWorkStatus.WORKING, null, deviceTime); |
| | | } |
| | | |
| | | private static TTestLiveServiceImpl liveService(TTest test, Instant now, boolean online, |
| | | DeviceWorkStatus workStatus, TTestMapper mapper, Instant deviceTime) |
| | | { |
| | | DeviceDiscoveryCandidateStore candidates = mock(DeviceDiscoveryCandidateStore.class); |
| | | TestDataObservationAdapter simulator = mock(TestDataObservationAdapter.class); |
| | | ITTestService tests = mock(ITTestService.class); |
| | |
| | | RealtimeSnapshot snapshot = new RealtimeSnapshot(identity, workStatus, 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()); |
| | | java.util.Map.of(), com.battery.device.api.model.DeviceConnectionStatus.ONLINE, deviceTime, List.of(), null); |
| | | DeviceDiscoveryCandidateStore.ChannelCandidate channel = new DeviceDiscoveryCandidateStore.ChannelCandidate( |
| | | identity, online, workStatus, now, snapshot); |
| | | DeviceDiscoveryCandidateStore.CabinetCandidate cabinet = new DeviceDiscoveryCandidateStore.CabinetCandidate( |
| | |
| | | when(simulator.testPlan(any(ChannelIdentity.class))).thenReturn(plan); |
| | | if (mapper != null && test.getBatteries().get(0).getCollectorId() != null) { |
| | | when(mapper.selectCollectorCode(7L)).thenReturn("collector-7"); |
| | | when(simulator.latestCollector("collector-7")).thenReturn( |
| | | when(simulator.latestCollector(org.mockito.ArgumentMatchers.nullable(String.class), org.mockito.ArgumentMatchers.eq("collector-7"))).thenReturn( |
| | | new TestDataObservationAdapter.CollectorRealtime("collector-7", online, 1000, List.of(), null)); |
| | | } |
| | | |