yeg
2026-08-30 56cddf53e7e71afad29885d7fcf773a222b95f6c
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
package com.ruoyi.system.service.impl;
 
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
 
import java.time.Instant;
import java.util.List;
import java.util.Set;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import com.ruoyi.system.domain.TTestCollectorExceptionInterval;
import com.ruoyi.system.domain.TTestCollectorSource;
import com.ruoyi.system.mapper.TTestMapper;
 
/** 采集器断线对账的来源级幂等与恢复边界测试。 */
@ExtendWith(MockitoExtension.class)
class CollectorDisconnectRecoveryServiceImplTest
{
    @Mock private TTestMapper mapper;
    @InjectMocks private CollectorDisconnectRecoveryServiceImpl service;
 
    @Test
    void opensOnlyOfflineSourceAndKeepsOtherSourcesIndependent()
    {
        TTestCollectorSource offline = source(10L, 20L, 8L, "COL-1", "S-01");
        TTestCollectorSource online = source(10L, 20L, 9L, "COL-2", "S-01");
        when(mapper.selectReceivingCollectorSources()).thenReturn(List.of(offline, online));
        when(mapper.selectOpenCollectorException(10L, 20L, 8L, "S-01")).thenReturn(null);
        when(mapper.selectOpenCollectorException(10L, 20L, 9L, "S-01")).thenReturn(null);
 
        service.reconcile(Set.of("COL-2"), Instant.parse("2026-08-30T09:00:00Z"));
 
        verify(mapper).insertCollectorExceptionInterval(any(TTestCollectorExceptionInterval.class));
        verify(mapper, never()).closeCollectorExceptionInterval(any(), any(), any());
    }
 
    @Test
    void closesOpenIntervalAtRecoveryBoundary()
    {
        TTestCollectorSource source = source(10L, 20L, 8L, "COL-1", "S-01");
        TTestCollectorExceptionInterval open = new TTestCollectorExceptionInterval();
        open.setIntervalId(99L);
        open.setIntervalStatus("OPEN");
        when(mapper.selectReceivingCollectorSources()).thenReturn(List.of(source));
        when(mapper.selectOpenCollectorException(10L, 20L, 8L, "S-01")).thenReturn(open);
 
        service.reconcile(Set.of("COL-1"), Instant.parse("2026-08-30T09:01:00Z"));
 
        verify(mapper).closeCollectorExceptionInterval(eq(99L), any(), any());
        verify(mapper, never()).insertCollectorExceptionInterval(any());
    }
 
    @Test
    void allowsAnotherDisconnectCycleAfterPreviousIntervalWasClosed()
    {
        TTestCollectorSource source = source(10L, 20L, 8L, "COL-1", "S-01");
        TTestCollectorExceptionInterval first = openInterval(99L);
        TTestCollectorExceptionInterval second = openInterval(100L);
        when(mapper.selectReceivingCollectorSources()).thenReturn(List.of(source));
        when(mapper.selectOpenCollectorException(10L, 20L, 8L, "S-01"))
                .thenReturn(null, first, null, second);
 
        service.reconcile(Set.of(), Instant.parse("2026-08-30T09:00:00Z"));
        service.reconcile(Set.of("COL-1"), Instant.parse("2026-08-30T09:01:00Z"));
        service.reconcile(Set.of(), Instant.parse("2026-08-30T09:02:00Z"));
        service.reconcile(Set.of("COL-1"), Instant.parse("2026-08-30T09:03:00Z"));
 
        verify(mapper, org.mockito.Mockito.times(2)).insertCollectorExceptionInterval(any());
        verify(mapper).closeCollectorExceptionInterval(eq(99L), any(), any());
        verify(mapper).closeCollectorExceptionInterval(eq(100L), any(), any());
    }
 
    private TTestCollectorExceptionInterval openInterval(Long intervalId)
    {
        TTestCollectorExceptionInterval interval = new TTestCollectorExceptionInterval();
        interval.setIntervalId(intervalId);
        interval.setIntervalStatus("OPEN");
        return interval;
    }
 
    private TTestCollectorSource source(Long testId, Long relationId, Long collectorId,
            String collectorCode, String channelCode)
    {
        TTestCollectorSource source = new TTestCollectorSource();
        source.setTestId(testId); source.setBatteryRelationId(relationId); source.setCollectorId(collectorId);
        source.setCollectorCode(collectorCode); source.setBatteryNo("BAT-01"); source.setChannelCode(channelCode);
        return source;
    }
}