From a4f06a9095a2eab0bb48b406c4609be6e70b8854 Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期四, 27 八月 2026 09:50:26 +0800
Subject: [PATCH] 设备管理-检测柜初版
---
ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/DeviceAdapterServiceImplTest.java | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 106 insertions(+), 1 deletions(-)
diff --git a/ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/DeviceAdapterServiceImplTest.java b/ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/DeviceAdapterServiceImplTest.java
index 2be39cd..41ee209 100644
--- a/ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/DeviceAdapterServiceImplTest.java
+++ b/ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/DeviceAdapterServiceImplTest.java
@@ -1,13 +1,18 @@
package com.ruoyi.system.service.impl;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import java.io.InputStream;
import java.math.BigDecimal;
+import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.List;
import java.util.Map;
@@ -18,11 +23,13 @@
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.device.api.DeviceAdapter;
import com.ruoyi.device.api.DeviceAdapterException;
import com.ruoyi.device.model.ChannelIdentity;
import com.ruoyi.device.model.DetectedChannel;
+import com.ruoyi.device.model.DetectedDeviceMetadata;
import com.ruoyi.device.model.DeviceWorkStatus;
import com.ruoyi.device.model.RealtimeSnapshot;
import com.ruoyi.device.registry.DeviceAdapterRegistry;
@@ -50,7 +57,8 @@
@BeforeEach
void setUp()
{
- service = new DeviceAdapterServiceImpl(adapterMapper, registry);
+ service = new DeviceAdapterServiceImpl(adapterMapper, registry,
+ new DeviceDiscoveryPersistenceService(adapterMapper));
adapter = new TDeviceAdapter();
adapter.setAdapterId(7L);
adapter.setAdapterCode("lab-bts");
@@ -61,6 +69,7 @@
adapter.setPollIntervalMs(5000);
adapter.setTimezoneId("Asia/Hong_Kong");
adapter.setReadOnly(true);
+ adapter.setCapabilities("{\"discovery\":true,\"realtimeObservation\":true,\"historyDownload\":true,\"control\":false}");
adapter.setStatus("0");
}
@@ -75,6 +84,23 @@
assertEquals(1, rows);
verify(registry).synchronize(any());
+ }
+
+ @Test
+ void springSelectsProductionConstructor()
+ {
+ try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext())
+ {
+ context.registerBean(TDeviceAdapterMapper.class, () -> org.mockito.Mockito.mock(TDeviceAdapterMapper.class));
+ context.registerBean(DeviceAdapterRegistry.class, () -> org.mockito.Mockito.mock(DeviceAdapterRegistry.class));
+ context.registerBean(DeviceDiscoveryPersistenceService.class,
+ () -> org.mockito.Mockito.mock(DeviceDiscoveryPersistenceService.class));
+ context.register(DeviceAdapterServiceImpl.class);
+
+ context.refresh();
+
+ assertNotNull(context.getBean(DeviceAdapterServiceImpl.class));
+ }
}
@Test
@@ -93,6 +119,31 @@
verify(adapterMapper, times(4)).upsertDetectedChannel(any(TDetectionChannel.class));
verify(adapterMapper, times(2)).updateDiscoverySuccess(eq(7L), any());
verify(adapterMapper, times(2)).updateDetectedCabinet(any(TDetectionCabinet.class));
+ }
+
+ @Test
+ void discoveryPersistsOptionalDeviceMetadataFromAdapterBoundary()
+ {
+ ChannelIdentity identity = new ChannelIdentity("lab-bts", 22, 8, 1, 1);
+ when(adapterMapper.selectDeviceAdapterById(7L)).thenReturn(adapter);
+ when(deviceAdapter.discoverChannels()).thenReturn(List.of(new DetectedChannel(identity, "127.0.0.8", true,
+ new DetectedDeviceMetadata("开发设备 8", "开发模拟器", "BTS Virtual Cabinet",
+ "02:44:00:16:00:08"))));
+ when(adapterMapper.selectCabinetIdByIdentity(7L, 22, 8)).thenReturn(null);
+ when(adapterMapper.insertDetectedCabinet(any(TDetectionCabinet.class))).thenAnswer(invocation -> {
+ invocation.getArgument(0, TDetectionCabinet.class).setCabinetId(18L);
+ return 1;
+ });
+ stubRegistryExecution();
+
+ service.discover(7L);
+
+ var cabinet = org.mockito.ArgumentCaptor.forClass(TDetectionCabinet.class);
+ verify(adapterMapper).insertDetectedCabinet(cabinet.capture());
+ assertEquals("开发设备 8", cabinet.getValue().getCabinetName());
+ assertEquals("开发模拟器", cabinet.getValue().getManufacturer());
+ assertEquals("BTS Virtual Cabinet", cabinet.getValue().getModel());
+ assertEquals("02:44:00:16:00:08", cabinet.getValue().getMacAddress());
}
@Test
@@ -117,6 +168,28 @@
}
@Test
+ void unavailableDevicePersistsExplicitOfflineFactsWithoutRealtimeInquiry()
+ {
+ when(adapterMapper.selectDeviceAdapterById(7L)).thenReturn(adapter);
+ when(deviceAdapter.discoverChannels()).thenReturn(List.of(
+ new DetectedChannel(new ChannelIdentity("lab-bts", 22, 1, 1, 1), "127.0.0.1", false),
+ new DetectedChannel(new ChannelIdentity("lab-bts", 22, 1, 1, 2), "127.0.0.1", false)));
+ when(adapterMapper.selectCabinetIdByIdentity(7L, 22, 1)).thenReturn(10L);
+ stubRegistryExecution();
+
+ service.discover(7L);
+
+ var cabinet = org.mockito.ArgumentCaptor.forClass(TDetectionCabinet.class);
+ var channels = org.mockito.ArgumentCaptor.forClass(TDetectionChannel.class);
+ verify(adapterMapper).updateDetectedCabinet(cabinet.capture());
+ verify(adapterMapper, times(2)).upsertDetectedChannel(channels.capture());
+ verify(deviceAdapter, never()).inquire(any());
+ assertEquals("OFFLINE", cabinet.getValue().getOnlineStatus());
+ assertTrue(channels.getAllValues().stream()
+ .allMatch(channel -> "OFFLINE".equals(channel.getOnlineStatus())));
+ }
+
+ @Test
void connectionFailureHasStableCodeAndLaterDiscoveryClearsError()
{
when(adapterMapper.selectDeviceAdapterById(7L)).thenReturn(adapter);
@@ -133,6 +206,38 @@
verify(adapterMapper).updateDiscoverySuccess(eq(7L), any());
}
+ @Test
+ void ensuresManagedAdapterFromApplicationProvidedConfiguration()
+ {
+ when(adapterMapper.selectDeviceAdapterByCode("lab-bts")).thenReturn(adapter);
+
+ TDeviceAdapter registered = service.ensureManagedAdapter(adapter);
+
+ verify(adapterMapper).upsertManagedDeviceAdapter(adapter);
+ assertEquals(adapter, registered);
+ }
+
+ @Test
+ void developmentSimulatorProvisioningIsIdempotentAndReadOnly()
+ {
+ String mapperXml;
+ try (InputStream input = getClass().getResourceAsStream("/mapper/system/TDeviceAdapterMapper.xml"))
+ {
+ if (input == null) throw new AssertionError("缺少设备适配器 Mapper");
+ mapperXml = new String(input.readAllBytes(), StandardCharsets.UTF_8);
+ }
+ catch (Exception exception)
+ {
+ throw new AssertionError("无法读取设备适配器 Mapper", exception);
+ }
+
+ assertTrue(mapperXml.contains("upsertManagedDeviceAdapter"));
+ assertTrue(mapperXml.contains("#{adapterCode}"));
+ assertTrue(mapperXml.contains("#{capabilities}"));
+ assertTrue(mapperXml.contains("on duplicate key update"));
+ assertTrue(mapperXml.contains("del_flag=0"));
+ }
+
@SuppressWarnings("unchecked")
private void stubRegistryExecution()
{
--
Gitblit v1.7.1