yeg
2026-08-26 de98fe81cca90dd855e0519f065e77fce56333ef
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package com.ruoyi.system.service.impl;
 
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.math.BigDecimal;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
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.DeviceWorkStatus;
import com.ruoyi.device.model.RealtimeSnapshot;
import com.ruoyi.device.registry.DeviceAdapterRegistry;
import com.ruoyi.system.domain.TDetectionCabinet;
import com.ruoyi.system.domain.TDetectionChannel;
import com.ruoyi.system.domain.TDeviceAdapter;
import com.ruoyi.system.mapper.TDeviceAdapterMapper;
import com.ruoyi.system.service.DeviceAdapterErrorCodes;
 
@ExtendWith(MockitoExtension.class)
class DeviceAdapterServiceImplTest
{
    @Mock
    private TDeviceAdapterMapper adapterMapper;
 
    @Mock
    private DeviceAdapterRegistry registry;
 
    @Mock
    private DeviceAdapter deviceAdapter;
 
    private DeviceAdapterServiceImpl service;
    private TDeviceAdapter adapter;
 
    @BeforeEach
    void setUp()
    {
        service = new DeviceAdapterServiceImpl(adapterMapper, registry);
        adapter = new TDeviceAdapter();
        adapter.setAdapterId(7L);
        adapter.setAdapterCode("lab-bts");
        adapter.setAdapterName("一号 BTS");
        adapter.setAdapterType("BTS");
        adapter.setHost("127.0.0.1");
        adapter.setPort(502);
        adapter.setPollIntervalMs(5000);
        adapter.setTimezoneId("Asia/Hong_Kong");
        adapter.setReadOnly(true);
        adapter.setStatus("0");
    }
 
    @Test
    void enablingAdapterSynchronizesRuntimeWithoutConstructingVendorClient()
    {
        adapter.setStatus("1");
        when(adapterMapper.selectDeviceAdapterById(7L)).thenReturn(adapter);
        when(adapterMapper.updateDeviceAdapterStatus(7L, "0", "admin")).thenReturn(1);
 
        int rows = service.changeStatus(7L, true, "admin");
 
        assertEquals(1, rows);
        verify(registry).synchronize(any());
    }
 
    @Test
    void repeatedDiscoveryUpsertsStableChannelIdentityWithoutDeletingMissingChannels()
    {
        when(adapterMapper.selectDeviceAdapterById(7L)).thenReturn(adapter);
        when(deviceAdapter.discoverChannels()).thenReturn(List.of(
                new DetectedChannel(new ChannelIdentity("lab-bts", 22, 1, 2, 3), "192.168.1.35", true),
                new DetectedChannel(new ChannelIdentity("lab-bts", 22, 1, 2, 4), "192.168.1.35", false)));
        stubRegistryExecution();
        when(adapterMapper.selectCabinetIdByIdentity(7L, 22, 1)).thenReturn(10L);
 
        assertEquals(2, service.discover(7L).channelCount());
        assertEquals(2, service.discover(7L).channelCount());
 
        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 discoveryPersistsRealtimeWorkStatusForAvailableChannels()
    {
        ChannelIdentity identity = new ChannelIdentity("lab-bts", 22, 1, 2, 3);
        when(adapterMapper.selectDeviceAdapterById(7L)).thenReturn(adapter);
        when(deviceAdapter.discoverChannels()).thenReturn(List.of(
                new DetectedChannel(identity, "192.168.1.35", true)));
        when(deviceAdapter.inquire(Set.of(identity))).thenReturn(Map.of(identity,
                new RealtimeSnapshot(identity, DeviceWorkStatus.WORKING, 1, 2, "cc", null,
                        BigDecimal.ONE, BigDecimal.TEN, null, null, 3L, 2L, null,
                        Instant.parse("2026-08-26T01:02:03Z"), Map.of())));
        when(adapterMapper.selectCabinetIdByIdentity(7L, 22, 1)).thenReturn(10L);
        stubRegistryExecution();
 
        service.discover(7L);
 
        var channel = org.mockito.ArgumentCaptor.forClass(TDetectionChannel.class);
        verify(adapterMapper).upsertDetectedChannel(channel.capture());
        assertEquals("WORKING", channel.getValue().getWorkStatus());
    }
 
    @Test
    void connectionFailureHasStableCodeAndLaterDiscoveryClearsError()
    {
        when(adapterMapper.selectDeviceAdapterById(7L)).thenReturn(adapter);
        when(deviceAdapter.discoverChannels())
                .thenThrow(new DeviceAdapterException("CONNECTION_FAILED", "connection refused", null))
                .thenReturn(List.of());
        stubRegistryExecution();
 
        ServiceException failure = assertThrows(ServiceException.class, () -> service.discover(7L));
        assertEquals(DeviceAdapterErrorCodes.DISCOVERY_FAILED, failure.getCode());
        verify(adapterMapper).updateDiscoveryFailure(7L, "CONNECTION_FAILED", "connection refused");
 
        assertEquals(0, service.discover(7L).channelCount());
        verify(adapterMapper).updateDiscoverySuccess(eq(7L), any());
    }
 
    @SuppressWarnings("unchecked")
    private void stubRegistryExecution()
    {
        when(registry.execute(eq("lab-bts"), any())).thenAnswer(invocation ->
                ((Function<DeviceAdapter, Object>) invocation.getArgument(1)).apply(deviceAdapter));
    }
}