package jnpf.dmsService; import jnpf.dmsEntity.permission.entity.DmsDocumentEntity; import jnpf.dmsEntity.permission.entity.DmsFileVersionEntity; import jnpf.dmsEntity.storage.DmsWorkflowSourceKey; import jnpf.dmsEntity.storage.enums.DmsWorkflowFileType; import jnpf.dmsEntity.storage.vo.DmsFileUploadVO; import jnpf.dmsIntegration.audit.DmsVersionStateAuditRow; import jnpf.dmsMapper.DmsDocumentMapper; import jnpf.dmsMapper.DmsFileObjectMapper; import jnpf.dmsMapper.DmsFileVersionMapper; import jnpf.dmsMapper.DmsVersionStateMapper; import jnpf.dmsService.search.DmsSearchIndexJobService; import jnpf.exception.DataException; import jnpf.flowable.WorkFlowApi; import jnpf.flowable.entity.TaskEntity; import jnpf.flowable.enums.TaskStatusEnum; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.util.UUID; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.*; class DmsWorkflowFileActivationServiceTest { private static final String TENANT = "tenant-1"; private static final String FLOW = "flow-1"; private static final String TASK = "task-1"; private static final UUID DOCUMENT = UUID.fromString("018f0000-0000-7000-8000-000000000801"); private static final UUID BASE = UUID.fromString("018f0000-0000-7000-8000-000000000802"); private static final UUID VERSION = UUID.fromString("018f0000-0000-7000-8000-000000000803"); private final WorkFlowApi workflowApi = mock(WorkFlowApi.class); private final DmsFileObjectMapper objectMapper = mock(DmsFileObjectMapper.class); private final DmsDocumentMapper documentMapper = mock(DmsDocumentMapper.class); private final DmsFileVersionMapper versionMapper = mock(DmsFileVersionMapper.class); private final DmsVersionStateMapper stateMapper = mock(DmsVersionStateMapper.class); private final DmsSearchIndexJobService searchJobs = mock(DmsSearchIndexJobService.class); private final DmsBusinessLifecycleGuard businessOccupancy = mock(DmsBusinessLifecycleGuard.class); private final DmsWorkflowFileActivationService service = new DmsWorkflowFileActivationService( workflowApi, objectMapper, documentMapper, versionMapper, stateMapper, searchJobs, businessOccupancy); @BeforeEach void setUp() { TaskEntity task = new TaskEntity(); task.setId(TASK); task.setFlowId(FLOW); task.setStatus(TaskStatusEnum.PASSED.getCode()); when(workflowApi.getInfoSubmit(TASK)).thenReturn(task); when(documentMapper.selectByTenantAndIdForUpdate(TENANT, DOCUMENT)) .thenReturn(new DmsDocumentEntity()); DmsVersionStateAuditRow pending = new DmsVersionStateAuditRow(); pending.setLifecycleStatus("PENDING_APPROVAL"); when(stateMapper.selectAuditState(TENANT, VERSION)).thenReturn(pending); when(stateMapper.activateWorkflowPending(TENANT, VERSION, FLOW, TASK, DmsWorkflowFileType.CREATE.name(), "approver-1")).thenReturn(1); when(stateMapper.activateWorkflowPending(TENANT, VERSION, FLOW, TASK, DmsWorkflowFileType.REVISE.name(), "approver-1")).thenReturn(1); } @Test void activatesStagedNewFileAndEnqueuesIndex() { DmsFileUploadVO staged = staged(DmsWorkflowFileType.CREATE); when(objectMapper.selectUploadBySource(TENANT, "jnpf-file", DmsWorkflowSourceKey.of(FLOW, TASK, DmsWorkflowFileType.CREATE))).thenReturn(staged); DmsFileUploadVO result = service.activate( TENANT, FLOW, TASK, DmsWorkflowFileType.CREATE, "approver-1"); assertSame(staged, result); assertEquals("EFFECTIVE", result.getLifecycleStatus()); verify(stateMapper).activateWorkflowPending(TENANT, VERSION, FLOW, TASK, DmsWorkflowFileType.CREATE.name(), "approver-1"); verify(searchJobs).enqueueContentUpsert(TENANT, DOCUMENT, VERSION, "abc"); } @Test void businessGuardRejectsBeforeAnyCenterMutationOrRowLock() { when(objectMapper.selectUploadBySource(TENANT, "jnpf-file", DmsWorkflowSourceKey.of(FLOW,TASK,DmsWorkflowFileType.CREATE))).thenReturn(staged(DmsWorkflowFileType.CREATE)); doThrow(new DataException("业务文件必须走完整批准批次")).when(businessOccupancy) .guardStandaloneActivation(TENANT,VERSION); assertThrows(DataException.class,()->service.activate(TENANT,FLOW,TASK,DmsWorkflowFileType.CREATE,"approver-1")); verifyNoInteractions(documentMapper,versionMapper,stateMapper,searchJobs); } @Test void revisionSupersedesBaseAndActivatesNewVersionInOrder() { DmsFileUploadVO staged = staged(DmsWorkflowFileType.REVISE); staged.setBaseFileVersionId(BASE); when(objectMapper.selectUploadBySource(TENANT, "jnpf-file", DmsWorkflowSourceKey.of(FLOW, TASK, DmsWorkflowFileType.REVISE))).thenReturn(staged); DmsFileVersionEntity current = new DmsFileVersionEntity(); current.setId(BASE); when(versionMapper.selectCurrentEffective(TENANT, DOCUMENT)).thenReturn(current); when(stateMapper.supersedeCurrent(TENANT, DOCUMENT, BASE, "D(01)", "approver-1")) .thenReturn(1); service.activate(TENANT, FLOW, TASK, DmsWorkflowFileType.REVISE, "approver-1"); org.mockito.InOrder ordered = inOrder(stateMapper); ordered.verify(stateMapper).supersedeCurrent(TENANT, DOCUMENT, BASE, "D(01)", "approver-1"); ordered.verify(stateMapper).activateWorkflowPending(TENANT, VERSION, FLOW, TASK, DmsWorkflowFileType.REVISE.name(), "approver-1"); } @Test void runningTaskCannotActivate() { TaskEntity running = new TaskEntity(); running.setId(TASK); running.setFlowId(FLOW); running.setStatus(TaskStatusEnum.RUNNING.getCode()); when(workflowApi.getInfoSubmit(TASK)).thenReturn(running); assertThrows(DataException.class, () -> service.activate( TENANT, FLOW, TASK, DmsWorkflowFileType.CREATE, "approver-1")); verifyNoInteractions(objectMapper); } private DmsFileUploadVO staged(DmsWorkflowFileType type) { DmsFileUploadVO value = new DmsFileUploadVO(); value.setDocumentId(DOCUMENT); value.setFileVersionId(VERSION); value.setVersionLabel(type == DmsWorkflowFileType.CREATE ? "D(00)" : "D(01)"); value.setChecksumSha256("abc"); value.setLifecycleStatus("PENDING_APPROVAL"); return value; } }