| | |
| | | import static org.junit.jupiter.api.Assertions.assertEquals; |
| | | import static org.junit.jupiter.api.Assertions.assertFalse; |
| | | import static org.junit.jupiter.api.Assertions.assertNotNull; |
| | | import static org.junit.jupiter.api.Assertions.assertNull; |
| | | import static org.junit.jupiter.api.Assertions.assertThrows; |
| | | import static org.junit.jupiter.api.Assertions.assertTrue; |
| | | |
| | |
| | | import org.mockito.junit.jupiter.MockitoExtension; |
| | | import com.ruoyi.common.exception.ServiceException; |
| | | import com.battery.business.domain.TCollector; |
| | | import com.battery.business.domain.TDeviceAdapter; |
| | | import com.battery.business.mapper.TCollectorMapper; |
| | | import com.battery.device.api.discovery.InMemoryDeviceDiscoveryCandidateStore; |
| | | import com.battery.device.api.discovery.DeviceDiscoveryCandidateStore.CollectorCandidate; |
| | | import com.battery.business.mapper.TDeviceAdapterMapper; |
| | | |
| | | /** |
| | | * 采集器 Service 单元测试。 |
| | | * |
| | | * <p>采集器按 ADR-0064 不建独立设备模型:登记不再依赖发现候选(真实来源不产出采集器候选), |
| | | * 由操作员手工登记来源身份,在线状态取所链接来源实例的连接结果。 |
| | | */ |
| | | @ExtendWith(MockitoExtension.class) |
| | | class TCollectorServiceImplTest |
| | |
| | | @Mock |
| | | private TCollectorMapper collectorMapper; |
| | | |
| | | @Mock |
| | | private TDeviceAdapterMapper adapterMapper; |
| | | |
| | | private TCollectorServiceImpl collectorService; |
| | | private InMemoryDeviceDiscoveryCandidateStore candidateStore; |
| | | |
| | | private TCollector collector; |
| | | |
| | | @BeforeEach |
| | | void setUp() |
| | | { |
| | | candidateStore = new InMemoryDeviceDiscoveryCandidateStore(); |
| | | collectorService = new TCollectorServiceImpl(collectorMapper, candidateStore); |
| | | java.time.Instant now = java.time.Instant.now(); |
| | | candidateStore.replaceCollectors("dev-sim", java.util.List.of(new CollectorCandidate( |
| | | "dev-sim", "COL-001", "192.168.1.10", "AA:BB:CC:DD:EE:FF", "一号采集器", |
| | | "开发模拟器", "Virtual Collector", 8, true, now, now.plusSeconds(60)))); |
| | | collectorService = new TCollectorServiceImpl(collectorMapper, adapterMapper); |
| | | collector = new TCollector(); |
| | | collector.setCollectorId(1L); |
| | | collector.setCollectorCode("COL-001"); |
| | |
| | | } |
| | | } |
| | | |
| | | /** 在线事实只有一个来源:所链接来源实例的连接结果;登记表里的存储列不再充当这个事实。 */ |
| | | @Test |
| | | void registeredCollectorCodeSqlShouldIgnoreDeletedRows() throws IOException |
| | | void onlineStatusSqlShouldDeriveFromLinkedAdapter() throws IOException |
| | | { |
| | | try (InputStream input = getClass().getResourceAsStream( |
| | | "/mapper/battery/TCollectorMapper.xml")) |
| | | { |
| | | assertNotNull(input); |
| | | String mapperXml = new String(input.readAllBytes(), StandardCharsets.UTF_8); |
| | | int selectStart = mapperXml.indexOf("<select id=\"selectRegisteredCollectorCodes\""); |
| | | assertTrue(selectStart >= 0); |
| | | int selectEnd = mapperXml.indexOf("</select>", selectStart); |
| | | String selectSql = mapperXml.substring(selectStart, selectEnd); |
| | | |
| | | assertTrue(selectSql.contains("where del_flag = '0'")); |
| | | int fragmentStart = mapperXml.indexOf("<sql id=\"derivedOnlineStatus\""); |
| | | assertTrue(fragmentStart >= 0, "在线状态的派生表达式应当是一个共用片段"); |
| | | String fragment = mapperXml.substring(fragmentStart, mapperXml.indexOf("</sql>", fragmentStart)); |
| | | assertTrue(fragment.contains("from t_device_adapter adapter_fact"), fragment); |
| | | // 存储列不再参与:只有派生的那个表达式。 |
| | | assertFalse(mapperXml.contains("upper(c.online_status)")); |
| | | // SELECT 与 WHERE 各用一次(WHERE 里不能用别名,所以走同一个片段)。 |
| | | assertEquals(2, mapperXml.split("<include refid=\"derivedOnlineStatus\" />", -1).length - 1); |
| | | } |
| | | } |
| | | |
| | | /** 登记不再要求发现候选:手工填写的来源身份即可落库。 */ |
| | | @Test |
| | | void insertCollectorShouldNotRequireADiscoveryCandidate() |
| | | { |
| | | collector.setCollectorId(null); |
| | | when(collectorMapper.insertCollector(any(TCollector.class))).thenReturn(1); |
| | | |
| | | assertEquals(1, collectorService.insertCollector(collector)); |
| | | |
| | | verify(collectorMapper).insertCollector(any(TCollector.class)); |
| | | } |
| | | |
| | | @Test |
| | | void insertCollectorShouldAcceptCollectorWithoutIpAndMac() |
| | | { |
| | | collector.setCollectorId(null); |
| | | collector.setIpAddress(null); |
| | | collector.setMacAddress(null); |
| | | when(collectorMapper.insertCollector(any(TCollector.class))).thenReturn(1); |
| | | |
| | | assertEquals(1, collectorService.insertCollector(collector)); |
| | | |
| | | ArgumentCaptor<TCollector> captor = ArgumentCaptor.forClass(TCollector.class); |
| | | verify(collectorMapper).insertCollector(captor.capture()); |
| | | assertNull(captor.getValue().getIpAddress()); |
| | | assertNull(captor.getValue().getMacAddress()); |
| | | } |
| | | |
| | | @Test |
| | |
| | | assertEquals("0", saved.getTestStatus()); |
| | | assertEquals("0", saved.getStatus()); |
| | | assertEquals("0", saved.getDelFlag()); |
| | | } |
| | | |
| | | @Test |
| | | void insertCollectorShouldRejectMalformedIpAndMacInsteadOfGuessing() |
| | | { |
| | | collector.setCollectorId(null); |
| | | collector.setIpAddress("invalid-host"); |
| | | collector.setMacAddress("AA:BB:CC:DD:EE:FF"); |
| | | |
| | | ServiceException ip = assertThrows(ServiceException.class, |
| | | () -> collectorService.insertCollector(collector)); |
| | | assertEquals("IP地址格式不正确", ip.getMessage()); |
| | | |
| | | collector.setIpAddress("192.168.1.10"); |
| | | collector.setMacAddress("invalid-mac"); |
| | | ServiceException mac = assertThrows(ServiceException.class, |
| | | () -> collectorService.insertCollector(collector)); |
| | | assertEquals("MAC地址格式不正确", mac.getMessage()); |
| | | verify(collectorMapper, never()).insertCollector(any(TCollector.class)); |
| | | } |
| | | |
| | | @Test |
| | | void insertCollectorShouldRejectUnknownLinkedSource() |
| | | { |
| | | collector.setCollectorId(null); |
| | | collector.setAdapterId(9L); |
| | | when(adapterMapper.selectDeviceAdapterById(9L)).thenReturn(null); |
| | | |
| | | ServiceException exception = assertThrows(ServiceException.class, |
| | | () -> collectorService.insertCollector(collector)); |
| | | |
| | | assertEquals("所链接的数据来源不存在", exception.getMessage()); |
| | | verify(collectorMapper, never()).insertCollector(any(TCollector.class)); |
| | | } |
| | | |
| | | /** 链接到来源实例后,登记保存该链接:采集器的辅助测量由它提供。 */ |
| | | @Test |
| | | void insertCollectorShouldPersistLinkedSource() |
| | | { |
| | | collector.setCollectorId(null); |
| | | collector.setAdapterId(3L); |
| | | when(adapterMapper.selectDeviceAdapterById(3L)).thenReturn(new TDeviceAdapter()); |
| | | when(collectorMapper.insertCollector(any(TCollector.class))).thenReturn(1); |
| | | |
| | | assertEquals(1, collectorService.insertCollector(collector)); |
| | | |
| | | ArgumentCaptor<TCollector> captor = ArgumentCaptor.forClass(TCollector.class); |
| | | verify(collectorMapper).insertCollector(captor.capture()); |
| | | assertEquals(Long.valueOf(3L), captor.getValue().getAdapterId()); |
| | | } |
| | | |
| | | @Test |
| | |
| | | } |
| | | |
| | | @Test |
| | | void insertCollectorShouldValidateAuthoritativeCandidateTopology() |
| | | { |
| | | collector.setCollectorId(null); |
| | | collector.setIpAddress("invalid-host"); |
| | | collector.setMacAddress("invalid-mac"); |
| | | collector.setChannelCount(99); |
| | | when(collectorMapper.insertCollector(any(TCollector.class))).thenReturn(1); |
| | | |
| | | assertEquals(1, collectorService.insertCollector(collector)); |
| | | |
| | | ArgumentCaptor<TCollector> captor = ArgumentCaptor.forClass(TCollector.class); |
| | | verify(collectorMapper).insertCollector(captor.capture()); |
| | | assertEquals("192.168.1.10", captor.getValue().getIpAddress()); |
| | | assertEquals("AA:BB:CC:DD:EE:FF", captor.getValue().getMacAddress()); |
| | | assertEquals(8, captor.getValue().getChannelCount()); |
| | | } |
| | | |
| | | @Test |
| | | void offlineCollectorCanBeRegisteredWithoutChangingOnlineFact() |
| | | { |
| | | java.time.Instant now = java.time.Instant.now(); |
| | | candidateStore.replaceCollectors("dev-sim", java.util.List.of(new CollectorCandidate( |
| | | "dev-sim", "COL-001", "192.168.1.10", "AA:BB:CC:DD:EE:FF", "一号采集器", |
| | | "开发模拟器", "Virtual Collector", 8, false, now, now.plusSeconds(60)))); |
| | | when(collectorMapper.insertCollector(any(TCollector.class))).thenReturn(1); |
| | | assertEquals(1, collectorService.insertCollector(collector)); |
| | | verify(collectorMapper).updateRegisteredObservation("COL-001", "OFFLINE"); |
| | | } |
| | | |
| | | @Test |
| | | void insertCollectorShouldRejectDuplicateCode() |
| | | { |
| | | collector.setCollectorId(null); |
| | |
| | | assertEquals(1, collectorService.updateCollector(collector)); |
| | | |
| | | verify(collectorMapper).updateCollector(collector); |
| | | } |
| | | |
| | | /** 编辑只提交可改字段:未提交的 IP/MAC 不能被当成"清空"。 */ |
| | | @Test |
| | | void updateCollectorShouldKeepUnsubmittedIpAndMac() |
| | | { |
| | | when(collectorMapper.selectCollectorById(1L)).thenReturn(collector); |
| | | when(collectorMapper.selectCollectorByCode("COL-001")).thenReturn(collector); |
| | | when(collectorMapper.selectCollectorByMacAddress("AA:BB:CC:DD:EE:FF")).thenReturn(collector); |
| | | when(collectorMapper.updateCollector(any(TCollector.class))).thenReturn(1); |
| | | TCollector edit = new TCollector(); |
| | | edit.setCollectorId(1L); |
| | | edit.setCollectorName("改名后"); |
| | | |
| | | assertEquals(1, collectorService.updateCollector(edit)); |
| | | |
| | | ArgumentCaptor<TCollector> captor = ArgumentCaptor.forClass(TCollector.class); |
| | | verify(collectorMapper).updateCollector(captor.capture()); |
| | | assertEquals("192.168.1.10", captor.getValue().getIpAddress()); |
| | | assertEquals("AA:BB:CC:DD:EE:FF", captor.getValue().getMacAddress()); |
| | | assertEquals("改名后", captor.getValue().getCollectorName()); |
| | | } |
| | | |
| | | @Test |
| | |
| | | assertEquals(1, collectorService.updateCollectorStatus(command)); |
| | | |
| | | verify(collectorMapper, never()).updateCollectorStatus(any(TCollector.class)); |
| | | } |
| | | |
| | | @Test |
| | | void selectRegisteredCollectorCodesShouldReturnUndeletedCodes() |
| | | { |
| | | when(collectorMapper.selectRegisteredCollectorCodes()).thenReturn(java.util.List.of("COL-001")); |
| | | |
| | | assertEquals(java.util.Set.of("COL-001"), collectorService.selectRegisteredCollectorCodes()); |
| | | } |
| | | |
| | | @Test |