refactor(pigx-flow): 移除测试文件并禁用 JimuReport 模块

- 删除 `MultiInstanceHandlerTests`、`ProcessNodeRecordServiceImplTests`、`ProcessTaskControllerTests`、`TaskServiceDelegateParticipationTests`、`TaskServiceImplTests` 五个测试类
- 注释 `pigx-visual/pom.xml` 中的 `pigx-jimu-platform` 模块,并添加启用说明注释
This commit is contained in:
PIGCLOUD committed 2026-08-01 17:24:24 +08:00
1 parent 55df29df99
commit 7461394f99
6 files changed
+2 -700

No files matched your search

@@ -1,49 +0,0 @@
package com.pig4cloud.pigx.flow.controller;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.flow.dto.AddSignTaskDto;
import com.pig4cloud.pigx.flow.service.ITaskService;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
class ProcessTaskControllerTests {
@Test
void originalApproverCanRequestBatchAddSignThroughPublicApi() throws Exception {
ITaskService taskService = mock(ITaskService.class);
when(taskService.addSign(org.mockito.ArgumentMatchers.any(AddSignTaskDto.class))).thenReturn(R.ok());
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new ProcessTaskController(taskService)).build();
mockMvc.perform(post("/task/addSign")
.contentType(MediaType.APPLICATION_JSON)
.content("""
{
"taskId": "12501",
"targetUserIdList": [31, 32],
"reason": "需要法务和财务共同确认"
}
"""))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(0));
ArgumentCaptor<AddSignTaskDto> captor = ArgumentCaptor.forClass(AddSignTaskDto.class);
verify(taskService).addSign(captor.capture());
assertThat(captor.getValue().getTaskId()).isEqualTo("12501");
assertThat(captor.getValue().getTargetUserIdList()).containsExactly(31L, 32L);
assertThat(captor.getValue().getReason()).isEqualTo("需要法务和财务共同确认");
}
}
@@ -1,67 +0,0 @@
package com.pig4cloud.pigx.flow.service.impl;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.flow.constant.NodeStatusEnum;
import com.pig4cloud.pigx.flow.dto.ProcessNodeRecordParamDto;
import com.pig4cloud.pigx.flow.entity.ProcessNodeRecord;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.junit.jupiter.api.extension.ExtendWith;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class ProcessNodeRecordServiceImplTests {
@Mock
private LambdaQueryChainWrapper<ProcessNodeRecord> activeRecordQuery;
private ProcessNodeRecordServiceImpl service;
@BeforeEach
void setUp() {
service = spy(new ProcessNodeRecordServiceImpl());
doReturn(activeRecordQuery).when(service).lambdaQuery();
when(activeRecordQuery.eq(any(SFunction.class), any())).thenReturn(activeRecordQuery);
when(activeRecordQuery.orderByAsc(any(SFunction.class))).thenReturn(activeRecordQuery);
when(activeRecordQuery.last(anyString())).thenReturn(activeRecordQuery);
}
@Test
void startReusesActiveRecordForSameProcessNodeRound() {
ProcessNodeRecord existing = new ProcessNodeRecord()
.setId(101L)
.setProcessInstanceId("process-1")
.setNodeId("approve-1")
.setStatus(NodeStatusEnum.JXZ.getCode());
when(activeRecordQuery.one()).thenReturn(existing);
R result = service.start(request());
assertThat(result.getCode()).isZero();
assertThat(result.getData()).isEqualTo(101L);
verify(service, never()).save(any(ProcessNodeRecord.class));
}
private ProcessNodeRecordParamDto request() {
ProcessNodeRecordParamDto request = new ProcessNodeRecordParamDto();
request.setFlowId("flow-1");
request.setProcessInstanceId("process-1");
request.setNodeId("approve-1");
request.setNodeName("会签审批");
request.setExecutionId("execution-2");
return request;
}
}
@@ -1,138 +0,0 @@
package com.pig4cloud.pigx.flow.service.impl;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.pig4cloud.pigx.admin.api.entity.SysUser;
import com.pig4cloud.pigx.admin.api.feign.RemoteUserService;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder;
import com.pig4cloud.pigx.common.security.service.PigxUser;
import com.pig4cloud.pigx.flow.constant.NodeStatusEnum;
import com.pig4cloud.pigx.flow.constant.ProcessInstanceConstant;
import com.pig4cloud.pigx.flow.dto.TaskParamDto;
import com.pig4cloud.pigx.flow.entity.ProcessNodeRecord;
import com.pig4cloud.pigx.flow.entity.ProcessNodeRecordAssignUser;
import com.pig4cloud.pigx.flow.mapper.ProcessNodeRecordMapper;
import com.pig4cloud.pigx.flow.mapper.ProcessTaskAddSignRecordMapper;
import com.pig4cloud.pigx.flow.service.IFlowableEngineService;
import com.pig4cloud.pigx.flow.service.IProcessCopyService;
import com.pig4cloud.pigx.flow.service.IProcessInstanceRecordService;
import com.pig4cloud.pigx.flow.service.IProcessNodeDataService;
import com.pig4cloud.pigx.flow.service.IProcessNodeRecordAssignUserService;
import com.pig4cloud.pigx.flow.service.IProcessNodeRecordService;
import com.pig4cloud.pigx.flow.service.IProcessService;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Answers;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import java.time.LocalDateTime;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class TaskServiceDelegateParticipationTests {
private static final long USER_ID = 11L;
private static final long TARGET_USER_ID = 31L;
private static final long TENANT_ID = 1L;
private static final long NODE_RECORD_ID = 101L;
private static final String TASK_ID = "task-1";
private static final String PROCESS_INSTANCE_ID = "process-1";
private static final String NODE_ID = "approve-1";
@Mock private IProcessService processService;
@Mock private IProcessCopyService processCopyService;
@Mock private IProcessNodeDataService nodeDataService;
@Mock private IProcessNodeRecordAssignUserService processNodeRecordAssignUserService;
@Mock private IProcessInstanceRecordService processInstanceRecordService;
@Mock private IProcessNodeRecordService processNodeRecordService;
@Mock private IFlowableEngineService flowableEngineService;
@Mock private TaskService taskService;
@Mock private HistoryService historyService;
@Mock private RuntimeService runtimeService;
@Mock private ObjectMapper objectMapper;
@Mock private RemoteUserService remoteUserService;
@Mock private ProcessNodeRecordMapper processNodeRecordMapper;
@Mock private ProcessTaskAddSignRecordMapper processTaskAddSignRecordMapper;
@Mock(answer = Answers.RETURNS_SELF) private TaskQuery taskQuery;
@Mock private Task task;
@Mock private BaseMapper<ProcessNodeRecordAssignUser> assignmentBaseMapper;
@InjectMocks private TaskServiceImpl taskServiceImpl;
@BeforeEach
void setCurrentUserAndTenant() {
PigxUser user = new PigxUser(USER_ID, "approver", List.of(), null, List.of(), List.of(), null, null,
"审批人", "审批人", null, TENANT_ID, "password", true, true, "sys", true,
LocalDateTime.now(), true, List.of());
SecurityContextHolder.getContext()
.setAuthentication(UsernamePasswordAuthenticationToken.authenticated(user, "password", List.of()));
TenantContextHolder.setTenantId(TENANT_ID);
}
@AfterEach
void clearCurrentUserAndTenant() {
SecurityContextHolder.clearContext();
TenantContextHolder.clear();
}
@Test
void delegateRejectsUserAlreadyParticipatingInCurrentRound() {
when(taskService.createTaskQuery()).thenReturn(taskQuery);
when(taskQuery.singleResult()).thenReturn(task);
when(task.getId()).thenReturn(TASK_ID);
when(task.getProcessInstanceId()).thenReturn(PROCESS_INSTANCE_ID);
when(task.getTaskDefinitionKey()).thenReturn(NODE_ID);
when(processNodeRecordAssignUserService.lambdaQuery())
.thenAnswer(invocation -> new LambdaQueryChainWrapper<>(assignmentBaseMapper));
when(assignmentBaseMapper.selectOne(any())).thenReturn(originalAssignment());
when(assignmentBaseMapper.selectList(any())).thenReturn(List.of(originalAssignment(), targetAssignment()));
when(processNodeRecordMapper.selectActiveByIdForUpdate(NODE_RECORD_ID, PROCESS_INSTANCE_ID, NODE_ID, TENANT_ID))
.thenReturn(new ProcessNodeRecord().setId(NODE_RECORD_ID));
TaskParamDto request = new TaskParamDto();
request.setTaskId(TASK_ID);
request.setTargetUserIdList(List.of(TARGET_USER_ID));
R result = taskServiceImpl.delegateTask(request);
assertThat(result.getCode()).isEqualTo(1);
assertThat(result.getMsg()).isEqualTo("委托目标已参与当前会签");
verify(flowableEngineService, never()).delegateTask(any(TaskParamDto.class));
}
private ProcessNodeRecordAssignUser originalAssignment() {
return new ProcessNodeRecordAssignUser()
.setNodeRecordId(NODE_RECORD_ID)
.setTaskId(TASK_ID)
.setUserId(USER_ID)
.setInitialUserId(USER_ID)
.setAssignmentOrigin(ProcessInstanceConstant.ASSIGNMENT_ORIGIN_ORIGINAL)
.setStatus(NodeStatusEnum.JXZ.getCode());
}
private ProcessNodeRecordAssignUser targetAssignment() {
return new ProcessNodeRecordAssignUser()
.setNodeRecordId(NODE_RECORD_ID)
.setTaskId("task-2")
.setUserId(TARGET_USER_ID)
.setStatus(NodeStatusEnum.JXZ.getCode());
}
}
@@ -1,405 +0,0 @@
package com.pig4cloud.pigx.flow.service.impl;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.pig4cloud.pigx.admin.api.entity.SysUser;
import com.pig4cloud.pigx.admin.api.feign.RemoteUserService;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder;
import com.pig4cloud.pigx.common.security.service.PigxUser;
import com.pig4cloud.pigx.flow.constant.NodeStatusEnum;
import com.pig4cloud.pigx.flow.constant.ProcessInstanceConstant;
import com.pig4cloud.pigx.flow.dto.AddSignResultDto;
import com.pig4cloud.pigx.flow.dto.AddSignTaskDto;
import com.pig4cloud.pigx.flow.dto.Node;
import com.pig4cloud.pigx.flow.entity.ProcessInstanceRecord;
import com.pig4cloud.pigx.flow.entity.ProcessNodeRecord;
import com.pig4cloud.pigx.flow.entity.ProcessNodeRecordAssignUser;
import com.pig4cloud.pigx.flow.entity.ProcessTaskAddSignRecord;
import com.pig4cloud.pigx.flow.mapper.ProcessNodeRecordMapper;
import com.pig4cloud.pigx.flow.mapper.ProcessTaskAddSignRecordMapper;
import com.pig4cloud.pigx.flow.service.IFlowableEngineService;
import com.pig4cloud.pigx.flow.service.IProcessCopyService;
import com.pig4cloud.pigx.flow.service.IProcessInstanceRecordService;
import com.pig4cloud.pigx.flow.service.IProcessNodeDataService;
import com.pig4cloud.pigx.flow.service.IProcessNodeRecordAssignUserService;
import com.pig4cloud.pigx.flow.service.IProcessNodeRecordService;
import com.pig4cloud.pigx.flow.service.IProcessService;
import com.pig4cloud.pigx.flow.service.ITaskService;
import org.flowable.common.engine.api.FlowableOptimisticLockingException;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.runtime.Execution;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionInterceptor;
import org.springframework.transaction.support.AbstractPlatformTransactionManager;
import org.springframework.transaction.support.DefaultTransactionStatus;
import java.time.LocalDateTime;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyMap;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class TaskServiceImplTests {
private static final long USER_ID = 11L;
private static final long TENANT_ID = 1L;
private static final long TARGET_USER_ID = 31L;
private static final long NODE_RECORD_ID = 101L;
private static final long ADD_SIGN_RECORD_ID = 901L;
private static final String TASK_ID = "12501";
private static final String ADDED_TASK_ID = "12502";
private static final String FLOW_ID = "flow-1";
private static final String PROCESS_DEFINITION_ID = FLOW_ID + ":1:deployment";
private static final String PROCESS_INSTANCE_ID = "process-1";
private static final String NODE_ID = "approve-1";
@Mock
private IProcessService processService;
@Mock
private IProcessCopyService processCopyService;
@Mock
private IProcessNodeDataService nodeDataService;
@Mock
private IProcessNodeRecordAssignUserService processNodeRecordAssignUserService;
@Mock
private IProcessInstanceRecordService processInstanceRecordService;
@Mock
private IProcessNodeRecordService processNodeRecordService;
@Mock
private IFlowableEngineService flowableEngineService;
@Mock
private TaskService taskService;
@Mock
private HistoryService historyService;
@Mock
private RuntimeService runtimeService;
@Spy
private ObjectMapper objectMapper = new ObjectMapper();
@Mock
private RemoteUserService remoteUserService;
@Mock
private ProcessNodeRecordMapper processNodeRecordMapper;
@Mock
private ProcessTaskAddSignRecordMapper processTaskAddSignRecordMapper;
@Mock(answer = Answers.RETURNS_SELF)
private TaskQuery taskQuery;
@Mock
private BaseMapper<ProcessInstanceRecord> processInstanceBaseMapper;
@Mock
private BaseMapper<ProcessNodeRecordAssignUser> assignmentBaseMapper;
@Mock
private Task sourceTask;
@Mock
private Task addedTask;
@Mock
private Execution addedExecution;
@InjectMocks
private TaskServiceImpl taskServiceImpl;
@BeforeEach
void setCurrentUserAndTenant() {
PigxUser user = new PigxUser(USER_ID, "approver", List.of(), null, List.of(), List.of(), null, null,
"审批人", "审批人", null, TENANT_ID, "password", true, true, "sys", true,
LocalDateTime.now(), true, List.of());
SecurityContextHolder.getContext()
.setAuthentication(UsernamePasswordAuthenticationToken.authenticated(user, "password", List.of()));
TenantContextHolder.setTenantId(TENANT_ID);
}
@AfterEach
void clearCurrentUserAndTenant() {
SecurityContextHolder.clearContext();
TenantContextHolder.clear();
}
@Test
void addSignRejectsEmptyTargetBatch() {
AddSignTaskDto request = request(List.of(), "需要共同确认");
R result = taskServiceImpl.addSign(request);
assertThat(result.getCode()).isEqualTo(1);
assertThat(result.getMsg()).isEqualTo("请选择加签人员");
}
@Test
void addSignRejectsDuplicateTargetUsers() {
AddSignTaskDto request = request(List.of(31L, 31L), "需要共同确认");
R result = taskServiceImpl.addSign(request);
assertThat(result.getCode()).isEqualTo(1);
assertThat(result.getMsg()).isEqualTo("加签人员不能重复");
}
@Test
void addSignRejectsReasonOutsideLengthLimit() {
AddSignTaskDto request = request(List.of(31L), "短");
R result = taskServiceImpl.addSign(request);
assertThat(result.getCode()).isEqualTo(1);
assertThat(result.getMsg()).isEqualTo("加签原因需为 2~100 字");
}
@Test
void addSignCreatesTaskAndAuditSnapshotForEligibleApprover() {
prepareTaskAndNode(addedTask);
prepareOriginalApprover();
prepareTargetValidation(List.of(originalAssignment()), validUser(TARGET_USER_ID, TENANT_ID));
prepareAuditInsert();
when(runtimeService.addMultiInstanceExecution(eq(NODE_ID), eq(PROCESS_INSTANCE_ID), anyMap()))
.thenReturn(addedExecution);
when(assignmentBaseMapper.selectCount(any())).thenReturn(1L);
R result = taskServiceImpl.addSign(request(List.of(TARGET_USER_ID), "需要共同确认"));
assertThat(result.getCode()).isZero();
assertThat(result.getData()).isInstanceOf(AddSignResultDto.class);
AddSignResultDto addSignResult = (AddSignResultDto) result.getData();
assertThat(addSignResult.getRecordId()).isEqualTo(ADD_SIGN_RECORD_ID);
assertThat(addSignResult.getTasks()).hasSize(1);
assertThat(addSignResult.getTasks().get(0).getTaskId()).isEqualTo(ADDED_TASK_ID);
assertThat(addSignResult.getTasks().get(0).getUserId()).isEqualTo(TARGET_USER_ID);
ArgumentCaptor<ProcessTaskAddSignRecord> recordCaptor = ArgumentCaptor
.forClass(ProcessTaskAddSignRecord.class);
verify(processTaskAddSignRecordMapper).insert(recordCaptor.capture());
ProcessTaskAddSignRecord record = recordCaptor.getValue();
assertThat(record.getSourceTaskId()).isEqualTo(TASK_ID);
assertThat(record.getAddedByUserId()).isEqualTo(USER_ID);
assertThat(record.getTargetUserIds()).isEqualTo("[31]");
assertThat(record.getParticipantUserIdsBefore()).isEqualTo("[11]");
assertThat(record.getParticipantUserIdsAfter()).isEqualTo("[11,31]");
verify(processTaskAddSignRecordMapper).updateById(record);
verify(processNodeRecordMapper).selectActiveByIdForUpdate(NODE_RECORD_ID, PROCESS_INSTANCE_ID, NODE_ID,
TENANT_ID);
verify(runtimeService).addMultiInstanceExecution(eq(NODE_ID), eq(PROCESS_INSTANCE_ID),
argThat(variables -> Long.valueOf(TARGET_USER_ID).equals(variables.get(NODE_ID + "_assignee_temp"))
&& Long.valueOf(ADD_SIGN_RECORD_ID)
.equals(variables.get(ProcessInstanceConstant.VAR_ADD_SIGN_RECORD_ID))));
}
@Test
void addSignRejectsProcessStarterEvenWhenStarterOwnsTask() {
prepareTaskAndNode(null);
prepareActiveAssignment();
when(processInstanceRecordService.lambdaQuery())
.thenAnswer(invocation -> new LambdaQueryChainWrapper<>(processInstanceBaseMapper));
when(processInstanceBaseMapper.selectCount(any())).thenReturn(1L);
R result = taskServiceImpl.addSign(request(List.of(TARGET_USER_ID), "需要共同确认"));
assertThat(result.getCode()).isEqualTo(1);
assertThat(result.getMsg()).isEqualTo("流程发起人不能发起加签");
verify(processTaskAddSignRecordMapper, never()).insert(any(ProcessTaskAddSignRecord.class));
}
@Test
void addSignRejectsTargetUserFromAnotherTenant() {
prepareTaskAndNode(null);
prepareOriginalApprover();
prepareTargetValidation(List.of(originalAssignment()), validUser(TARGET_USER_ID, TENANT_ID + 1));
R result = taskServiceImpl.addSign(request(List.of(TARGET_USER_ID), "需要共同确认"));
assertThat(result.getCode()).isEqualTo(1);
assertThat(result.getMsg()).isEqualTo("加签用户不存在或不属于当前租户");
verify(processTaskAddSignRecordMapper, never()).insert(any(ProcessTaskAddSignRecord.class));
}
@Test
void addSignRejectsUserAlreadyParticipatingInCurrentCountersign() {
prepareTaskAndNode(null);
prepareOriginalApprover();
ProcessNodeRecordAssignUser existingParticipant = new ProcessNodeRecordAssignUser()
.setNodeRecordId(NODE_RECORD_ID)
.setUserId(TARGET_USER_ID);
prepareTargetValidation(List.of(originalAssignment(), existingParticipant),
validUser(TARGET_USER_ID, TENANT_ID));
R result = taskServiceImpl.addSign(request(List.of(TARGET_USER_ID), "需要共同确认"));
assertThat(result.getCode()).isEqualTo(1);
assertThat(result.getMsg()).isEqualTo("用户已参与当前会签:目标审批人");
verify(processTaskAddSignRecordMapper, never()).insert(any(ProcessTaskAddSignRecord.class));
}
@Test
void addSignRollsBackAuditWhenFlowableReportsConcurrentChange() {
prepareTaskAndNode(null);
prepareOriginalApprover();
prepareTargetValidation(List.of(originalAssignment()), validUser(TARGET_USER_ID, TENANT_ID));
prepareAuditInsert();
when(runtimeService.addMultiInstanceExecution(anyString(), anyString(), anyMap()))
.thenThrow(new FlowableOptimisticLockingException("conflict"));
RecordingTransactionManager transactionManager = new RecordingTransactionManager();
R result = transactionalService(transactionManager)
.addSign(request(List.of(TARGET_USER_ID), "需要共同确认"));
assertThat(result.getCode()).isEqualTo(1);
assertThat(result.getMsg()).isEqualTo("节点状态已变化,请刷新后重试");
assertThat(transactionManager.rolledBack).isTrue();
assertThat(transactionManager.committed).isFalse();
verify(processTaskAddSignRecordMapper).insert(any(ProcessTaskAddSignRecord.class));
verify(processTaskAddSignRecordMapper, never()).updateById(any(ProcessTaskAddSignRecord.class));
}
private void prepareTaskAndNode(Task taskCreatedAfterAddSign) {
when(taskService.createTaskQuery()).thenReturn(taskQuery);
if (taskCreatedAfterAddSign == null) {
when(taskQuery.singleResult()).thenReturn(sourceTask);
}
else {
when(taskQuery.singleResult()).thenReturn(sourceTask, taskCreatedAfterAddSign);
}
when(sourceTask.getProcessInstanceId()).thenReturn(PROCESS_INSTANCE_ID);
when(sourceTask.getTaskDefinitionKey()).thenReturn(NODE_ID);
when(sourceTask.getProcessDefinitionId()).thenReturn(PROCESS_DEFINITION_ID);
if (taskCreatedAfterAddSign != null) {
when(taskCreatedAfterAddSign.getId()).thenReturn(ADDED_TASK_ID);
}
ProcessNodeRecord nodeRecord = new ProcessNodeRecord().setId(NODE_RECORD_ID);
when(processNodeRecordMapper.selectActiveByIdForUpdate(NODE_RECORD_ID, PROCESS_INSTANCE_ID, NODE_ID,
TENANT_ID))
.thenReturn(nodeRecord);
Node node = new Node();
node.setAssignedType(ProcessInstanceConstant.AssignedTypeClass.ROLE);
node.setMultipleMode(ProcessInstanceConstant.MULTIPLE_MODE_AL_SAME);
node.setAllowAddSign(true);
when(nodeDataService.getNodeData(FLOW_ID, NODE_ID)).thenReturn(R.ok(node));
}
private void prepareOriginalApprover() {
prepareActiveAssignment();
when(sourceTask.getAssignee()).thenReturn(String.valueOf(USER_ID));
when(processInstanceRecordService.lambdaQuery())
.thenAnswer(invocation -> new LambdaQueryChainWrapper<>(processInstanceBaseMapper));
}
private void prepareActiveAssignment() {
when(sourceTask.getId()).thenReturn(TASK_ID);
when(processNodeRecordAssignUserService.lambdaQuery())
.thenAnswer(invocation -> new LambdaQueryChainWrapper<>(assignmentBaseMapper));
when(assignmentBaseMapper.selectOne(any())).thenReturn(originalAssignment());
}
private void prepareTargetValidation(List<ProcessNodeRecordAssignUser> participants, SysUser targetUser) {
when(assignmentBaseMapper.selectList(any())).thenReturn(participants);
when(remoteUserService.getUserById(List.of(TARGET_USER_ID))).thenReturn(R.ok(List.of(targetUser)));
}
private void prepareAuditInsert() {
when(processTaskAddSignRecordMapper.insert(any(ProcessTaskAddSignRecord.class))).thenAnswer(invocation -> {
ProcessTaskAddSignRecord record = invocation.getArgument(0);
record.setId(ADD_SIGN_RECORD_ID);
return 1;
});
}
private ProcessNodeRecordAssignUser originalAssignment() {
return new ProcessNodeRecordAssignUser()
.setNodeRecordId(NODE_RECORD_ID)
.setTaskId(TASK_ID)
.setUserId(USER_ID)
.setInitialUserId(USER_ID)
.setAssignmentOrigin(ProcessInstanceConstant.ASSIGNMENT_ORIGIN_ORIGINAL)
.setStatus(NodeStatusEnum.JXZ.getCode());
}
private SysUser validUser(long userId, long tenantId) {
SysUser user = new SysUser();
user.setUserId(userId);
user.setUsername("target");
user.setName("目标审批人");
user.setTenantId(tenantId);
user.setDelFlag("0");
user.setLockFlag("0");
return user;
}
private ITaskService transactionalService(RecordingTransactionManager transactionManager) {
ProxyFactory proxyFactory = new ProxyFactory(taskServiceImpl);
proxyFactory.addInterface(ITaskService.class);
proxyFactory.addAdvice(new TransactionInterceptor(transactionManager,
new AnnotationTransactionAttributeSource()));
return (ITaskService) proxyFactory.getProxy();
}
private AddSignTaskDto request(List<Long> userIds, String reason) {
AddSignTaskDto request = new AddSignTaskDto();
request.setTaskId(TASK_ID);
request.setTargetUserIdList(userIds);
request.setReason(reason);
return request;
}
private static final class RecordingTransactionManager extends AbstractPlatformTransactionManager {
private boolean committed;
private boolean rolledBack;
@Override
protected Object doGetTransaction() {
return new Object();
}
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
}
@Override
protected void doCommit(DefaultTransactionStatus status) {
committed = true;
}
@Override
protected void doRollback(DefaultTransactionStatus status) {
rolledBack = true;
}
}
}
@@ -1,40 +0,0 @@
package com.pig4cloud.pigx.flow.support.node;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.flow.constant.ProcessInstanceConstant;
import com.pig4cloud.pigx.flow.dto.Node;
import com.pig4cloud.pigx.flow.service.IProcessNodeDataService;
import org.flowable.engine.impl.persistence.entity.ExecutionEntityImpl;
import org.junit.jupiter.api.Test;
import java.util.Collections;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
class MultiInstanceHandlerTests {
@Test
void countersignWaitsForDynamicallyExpandedInstanceCount() {
IProcessNodeDataService nodeDataService = mock(IProcessNodeDataService.class);
Node node = new Node();
node.setMultipleMode(ProcessInstanceConstant.MULTIPLE_MODE_AL_SAME);
when(nodeDataService.getNodeData("flow-1", "approve-1")).thenReturn(R.ok(node));
MultiInstanceHandler handler = new MultiInstanceHandler(nodeDataService, Collections.emptyMap(),
new ObjectMapper());
ExecutionEntityImpl execution = mock(ExecutionEntityImpl.class);
when(execution.getProcessDefinitionKey()).thenReturn("flow-1");
when(execution.getCurrentActivityId()).thenReturn("approve-1");
when(execution.getVariable("approve-1_approve_condition")).thenReturn(true);
when(execution.getVariable("nrOfInstances")).thenReturn(3);
when(execution.getVariable("nrOfCompletedInstances")).thenReturn(2);
assertThat(handler.completionCondition(execution)).isFalse();
when(execution.getVariable("nrOfCompletedInstances")).thenReturn(3);
assertThat(handler.completionCondition(execution)).isTrue();
}
}
+2 -1
View File
@@ -36,10 +36,11 @@
<module>pigx-codegen</module>
<module>pigx-daemon-elastic-job</module>
<module>pigx-daemon-quartz</module>
<module>pigx-jimu-platform</module>
<module>pigx-pay-platform</module>
<module>pigx-monitor</module>
<module>pigx-mp-platform</module>
<module>pigx-xxl-job-admin</module>
<!-- JimuReport 启用说明:https://ourl.cn/R7bKJ8 -->
<!--<module>pigx-jimu-platform</module>-->
</modules>
</project>