刘光辉
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
107
108
109
110
111
112
113
114
package jnpf.dmsService;
 
import jnpf.dmsEntity.storage.approval.DmsDisableOccupancy;
import jnpf.dmsEntity.storage.form.DmsDisableSubmitValidationForm;
import jnpf.dmsMapper.DmsDisableApplicationMapper;
import jnpf.exception.DataException;
import jnpf.flowable.WorkFlowApi;
import jnpf.flowable.entity.TaskEntity;
import org.junit.jupiter.api.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.test.util.ReflectionTestUtils;
import java.util.*;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
 
class DmsDisableOccupancyServiceTest {
    DmsDisableApplicationMapper mapper=mock(DmsDisableApplicationMapper.class);
    WorkFlowApi workflow=mock(WorkFlowApi.class);
    DmsDisableOccupancyService service=new DmsDisableOccupancyService(mapper,workflow);
    TaskEntity task; DmsDisableOccupancy application;
    @BeforeEach void init() {
        ReflectionTestUtils.setField(service,"enabled",true);
        task=new TaskEntity();task.setId("task");task.setFlowId("flow");task.setTemplateId("template");
        application=new DmsDisableOccupancy();application.setApplicationId("app");application.setFlowId("template");application.setCreatorUserId("applicant");
        when(workflow.getInfoSubmit("task")).thenReturn(task);
        when(mapper.application("tenant","task","yichexiao")).thenReturn(application);
    }
    void state(int status, boolean ended) {task.setStatus(status);task.setEndTime(ended?new Date():null);application.setFlowState(status);}
    DmsDisableOccupancy file(String id) {DmsDisableOccupancy r=new DmsDisableOccupancy();r.setFileId(id);r.setFolderId("folder-"+id);return r;}
    boolean event(String type) {return service.onEvent("tenant","flow","task","yichexiao",type);}
    @Test void submittedRowsProduceTenantTaskAndDirectorySnapshot() {
        state(1,false);DmsDisableOccupancy row=file("main");
        when(mapper.applicationFiles("tenant","app","yichexiao")).thenReturn(List.of(row));
        when(mapper.selectedFiles("tenant",List.of("main"))).thenReturn(List.of(row));
        assertFalse(event("start"));
        verify(mapper).conflictingFiles("tenant",List.of("main"),"task");
        verify(mapper).releaseTask("tenant","task","yichexiao");verify(mapper).occupy(row);
        assertEquals("tenant",row.getTenantId());assertEquals("task",row.getTaskId());assertEquals("app",row.getApplicationId());
        assertEquals("folder-main",row.getFolderId());
    }
    @Test void resubmitReplacesOnlyOwnSnapshotAfterCheckingLatestSelection() {
        state(1,false);DmsDisableOccupancy current=file("replacement");
        when(mapper.applicationFiles("tenant","app","yichexiao")).thenReturn(List.of(current));
        when(mapper.selectedFiles("tenant",List.of("replacement"))).thenReturn(List.of(current));
        event("start");
        org.mockito.InOrder order=inOrder(mapper);
        order.verify(mapper).application("tenant","task","yichexiao");
        order.verify(mapper).applicationFiles("tenant","app","yichexiao");
        order.verify(mapper).selectedFiles("tenant",List.of("replacement"));
        order.verify(mapper).conflictingFiles("tenant",List.of("replacement"),"task");
        order.verify(mapper).releaseTask("tenant","task","yichexiao");
        order.verify(mapper).occupy(current);
    }
    @ParameterizedTest @ValueSource(ints={0,1,3,4,5,6,7,8,9,10})
    void noReleaseWithoutTrueEndEvenForReturnAndReject(int status) {
        state(status,false);assertFalse(event(status==8?"back":"reject"));
        verify(mapper,never()).releaseTask(any(),any(),any());verify(mapper,never()).occupy(any());
    }
    @ParameterizedTest @ValueSource(ints={3,4,7,9})
    void trueUnsuccessfulEndReleasesOwnTaskOnly(int status) {
        state(status,true);assertFalse(event("end"));verify(mapper).releaseTask("tenant","task","yichexiao");
        verify(mapper,never()).applicationFiles(any(),any(),any());
    }
    @Test void approvedEndDispatchesDisableAndKeepsOccupancyUntilProjection() {
        state(2,true);assertTrue(event("end"));verify(mapper,never()).releaseTask(any(),any(),any());
    }
    @Test void lateStartCannotReoccupyFinishedApprovedFile() {
        state(2,true);assertFalse(event("start"));verify(mapper,never()).occupy(any());
    }
    @Test void eventCannotChangeAnotherNativeApplication() {
        state(1,false);application.setFlowId("another");assertThrows(DataException.class,()->event("start"));
        verify(mapper,never()).releaseTask(any(),any(),any());
    }
    DmsDisableSubmitValidationForm form(String taskId) {
        DmsDisableSubmitValidationForm f=new DmsDisableSubmitValidationForm();f.setFlowId("flow");f.setTaskId(taskId);f.setFileIds(List.of("main"));
        when(mapper.selectedFiles("tenant",List.of("main"))).thenReturn(List.of(file("main")));return f;
    }
    @Test void crossOperationConflictBlocksBeforeNativeSubmit() {
        DmsDisableSubmitValidationForm f=form(null);when(mapper.conflictingFiles("tenant",List.of("main"),null)).thenReturn(1);
        assertThrows(DataException.class,()->service.validateSubmission("tenant","applicant","yishixiao",f));
        verify(mapper,never()).occupy(any());
    }
    @ParameterizedTest @ValueSource(ints={0,8,9})
    void ownDraftReturnedOrRecalledApplicationUsesNativeCreatorWhenWorkflowOmitsIt(int status) {
        state(status,false);service.validateSubmission("tenant","applicant","yichexiao",form("task"));
        verify(mapper).conflictingFiles("tenant",List.of("main"),"task");verify(mapper,never()).releaseTask(any(),any(),any());
    }
    @Test void cannotExcludeAnotherApplicantsOccupancy() {
        state(8,false);assertThrows(DataException.class,()->service.validateSubmission("tenant","other","yichexiao",form("task")));
        verify(mapper,never()).conflictingFiles(any(),any(),any());
    }
    @Test void activeChangedOrFinishedTaskCannotBeUsedAsNewSubmissionExclusion() {
        state(1,false);assertThrows(DataException.class,()->service.validateSubmission("tenant","applicant","yichexiao",form("task")));
        state(3,true);assertThrows(DataException.class,()->service.validateSubmission("tenant","applicant","yichexiao",form("task")));
    }
    @Test void nativeApprovalPreflightAllowsUnchangedOwnApplicationForReviewer() {
        state(1,false);when(mapper.applicationFiles("tenant","app","yichexiao")).thenReturn(List.of(file("main")));
        service.validateSubmission("tenant","reviewer","yichexiao",form("task"));
        verify(mapper).conflictingFiles("tenant",List.of("main"),"task");
        verify(mapper,never()).occupy(any());
    }
    @Test void startConflictDoesNotClearExistingSnapshot() {
        state(1,false);DmsDisableOccupancy row=file("main");when(mapper.applicationFiles("tenant","app","yichexiao")).thenReturn(List.of(row));
        when(mapper.selectedFiles("tenant",List.of("main"))).thenReturn(List.of(row));
        when(mapper.conflictingFiles("tenant",List.of("main"),"task")).thenReturn(1);
        assertThrows(DataException.class,()->event("start"));verify(mapper,never()).releaseTask(any(),any(),any());
    }
    @Test void disabledFeatureKeepsExistingEndCallbackUsableWithoutTechnicalTable() {
        ReflectionTestUtils.setField(service,"enabled",false);state(3,true);assertFalse(event("end"));
        state(2,true);assertTrue(event("end"));verify(mapper,never()).releaseTask(any(),any(),any());
        assertThrows(DataException.class,()->event("start"));
    }
}