刘光辉
4 小时以前 06f314545ac3514d7ce28939920866ae8188d31c
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
package jnpf.dmsService;
 
import jnpf.dmsEntity.kanwu.DmsXiudingKanwuRow;
import jnpf.dmsMapper.DmsXiudingKanwuMapper;
import jnpf.dmsIntegration.audit.DmsBusinessChangeAudit;
import jnpf.exception.DataException;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.*;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.*;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
 
@ExtendWith(MockitoExtension.class)
class DmsXiudingKanwuServiceTest {
    @Mock DmsXiudingKanwuMapper mapper;
    @Mock DmsBusinessChangeAudit audit;
    @InjectMocks DmsXiudingKanwuService service;
    DmsXiudingKanwuRow row(String id) {
        DmsXiudingKanwuRow row = new DmsXiudingKanwuRow();
        row.setKanwuZixiangId(id); row.setKanwuShenqingId("request");
        row.setWenjianId("file"); row.setBanbenId("base"); row.setKanwuNeirong("content");
        row.setChuliJielun("yixiugai_queren"); row.setChuliYuanyin("已核对并修订");
        row.setChuliRenId("drafter"); row.setChuliShijian(new Date(1000));
        return row;
    }
    void arrange(List<DmsXiudingKanwuRow> handled, List<DmsXiudingKanwuRow> approved) {
        when(mapper.selectHandlingForUpdate("tenant", "audit")).thenReturn(handled);
        when(mapper.selectApprovedForUpdate("tenant", "file", "base")).thenReturn(approved);
    }
    List<DmsXiudingKanwuRow> load() { return service.loadAndValidate("tenant", "audit", "file", "base"); }
    @Test void acceptsEmptyScope() { arrange(List.of(), List.of()); assertTrue(load().isEmpty()); }
    @Test void sortsWithoutMutatingMapperListAndNormalizesFiles() {
        DmsXiudingKanwuRow handled = row("a"), source = row("a");
        handled.setFujian("[{\"url\":\"x\",\"name\":\"n\"}]");
        source.setFujian("[{\"name\":\"n\",\"url\":\"x\"}]");
        DmsXiudingKanwuRow empty = row("b"); empty.setFujian("[]");
        arrange(List.of(empty, handled), List.of(source, row("b")));
        assertEquals(List.of("a", "b"), load().stream().map(DmsXiudingKanwuRow::getKanwuZixiangId).toList());
    }
    @ParameterizedTest @ValueSource(strings={"yixiugai_queren", "bucaina"})
    void bothOutcomesRequireReasonAndAuditFields(String outcome) {
        DmsXiudingKanwuRow handled = row("a"); handled.setChuliJielun(outcome);
        arrange(List.of(handled), List.of(row("a"))); assertEquals(outcome, load().get(0).getChuliJielun());
        handled.setChuliYuanyin(" "); assertThrows(DataException.class, this::load);
        handled.setChuliYuanyin("reason"); handled.setChuliRenId(null); assertThrows(DataException.class, this::load);
        handled.setChuliRenId("drafter"); handled.setChuliShijian(null); assertThrows(DataException.class, this::load);
    }
    @Test void rejectsMissingNewApprovedNote() { arrange(List.of(row("a")), List.of(row("a"), row("b"))); assertThrows(DataException.class, this::load); }
    @Test void rejectsUnapprovedOrOutOfScopeNote() { arrange(List.of(row("other")), List.of(row("a"))); assertThrows(DataException.class, this::load); }
    @Test void rejectsDuplicateHandling() { arrange(List.of(row("a"), row("a")), List.of(row("a"), row("b"))); assertThrows(DataException.class, this::load); }
    @Test void rejectsChangedContentOrFiles() {
        DmsXiudingKanwuRow handled = row("a"); arrange(List.of(handled), List.of(row("a")));
        handled.setKanwuNeirong("changed"); assertThrows(DataException.class, this::load);
        handled.setKanwuNeirong("content"); handled.setFujian("[{}]"); assertThrows(DataException.class, this::load);
        handled.setFujian("{}"); assertThrows(DataException.class, this::load);
        handled.setFujian("invalid"); assertThrows(DataException.class, this::load);
    }
    @Test void rejectsUnknownOutcome() { DmsXiudingKanwuRow handled=row("a");handled.setChuliJielun("yes");arrange(List.of(handled),List.of(row("a")));assertThrows(DataException.class,this::load); }
    @Test void preservesFirstProcessingAuditAndOnlyClosesUnprocessedRows() {
        DmsXiudingKanwuRow processed = row("a"); processed.setShifouYichuli("yes");
        arrange(List.of(row("a"), row("b")), List.of(processed, row("b")));
        List<DmsXiudingKanwuRow> verified = load();
        when(mapper.markProcessed("tenant", verified.get(1))).thenReturn(1);
        Date writtenAt = new Date(9000);
        Map<String, Object> before = DmsBusinessChangeAudit.values("shifou_yichuli", null,
                "chuliren", "previous", "chuli_shijian", null);
        Map<String, Object> after = DmsBusinessChangeAudit.values("shifou_yichuli", "yes",
                "chuliren", "drafter", "chuli_shijian", writtenAt);
        when(mapper.selectProcessingState("tenant", "b")).thenReturn(before, after);
        service.complete("tenant", "audit", verified);
        verify(mapper, never()).markProcessed("tenant", verified.get(0));
        verify(mapper).markProcessed("tenant", verified.get(1));
        verify(mapper, never()).selectProcessingState("tenant", "a");
        verify(audit).record(eq("tenant"), eq("DMS_REVISION_ERRATA_PROCESSED"),
                eq("修订生效后回写勘误处理状态"), eq("dms_wenjian_kanwu_shenqing_zixiang"), eq("b"),
                eq(before), eq(after), eq("已核对并修订"), argThat(context ->
                        "audit".equals(context.get("xiuding_shenhe_id"))
                                && "request".equals(context.get("kanwu_shenqing_id"))
                                && "yixiugai_queren".equals(context.get("chuli_jielun"))
                                && new Date(1000).equals(context.get("chuli_shijian"))));
        verifyNoMoreInteractions(audit);
    }
    @Test void emptyOrAlreadyProcessedRowsDoNotCreateAuditEvents() {
        service.complete("tenant", "audit", List.of());
        DmsXiudingKanwuRow processed = row("a");
        processed.setAlreadyProcessed(true);
        service.complete("tenant", "audit", List.of(processed));
        verifyNoInteractions(mapper, audit);
    }
    @Test void updateFailurePropagatesToEffectiveTransaction() {
        when(mapper.selectProcessingState("tenant", "a")).thenReturn(Map.of("id", "a"));
        assertThrows(DataException.class, () -> service.complete("tenant", "audit", List.of(row("a"))));
        verify(mapper).markProcessed(eq("tenant"), any());
        verifyNoInteractions(audit);
    }
    @Test void missingSnapshotDoesNotFabricateAuditValues() {
        when(mapper.selectProcessingState("tenant", "a")).thenReturn(null);
        assertThrows(DataException.class, () -> service.complete("tenant", "audit", List.of(row("a"))));
        verify(mapper, never()).markProcessed(anyString(), any());
        verifyNoInteractions(audit);
    }
}