增加工作流代码可正常启动
This commit is contained in:
parent
2c39b79515
commit
bdbd4528a5
@ -1,325 +0,0 @@
|
|||||||
package com.qqchen.deploy.backend.workflow.engine;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.qqchen.deploy.backend.workflow.dto.WorkflowDefinitionDTO;
|
|
||||||
import com.qqchen.deploy.backend.workflow.engine.context.DefaultWorkflowContext;
|
|
||||||
import com.qqchen.deploy.backend.workflow.engine.executor.*;
|
|
||||||
import com.qqchen.deploy.backend.workflow.entity.NodeInstance;
|
|
||||||
import com.qqchen.deploy.backend.workflow.entity.WorkflowDefinition;
|
|
||||||
import com.qqchen.deploy.backend.workflow.entity.WorkflowInstance;
|
|
||||||
import com.qqchen.deploy.backend.workflow.enums.NodeStatusEnum;
|
|
||||||
import com.qqchen.deploy.backend.workflow.enums.NodeTypeEnum;
|
|
||||||
import com.qqchen.deploy.backend.workflow.enums.WorkflowStatusEnum;
|
|
||||||
import com.qqchen.deploy.backend.workflow.repository.INodeInstanceRepository;
|
|
||||||
import com.qqchen.deploy.backend.workflow.repository.IWorkflowDefinitionRepository;
|
|
||||||
import com.qqchen.deploy.backend.workflow.repository.IWorkflowInstanceRepository;
|
|
||||||
import com.qqchen.deploy.backend.workflow.service.IWorkflowDefinitionService;
|
|
||||||
import com.qqchen.deploy.backend.workflow.service.IWorkflowLogService;
|
|
||||||
import com.qqchen.deploy.backend.workflow.service.IWorkflowVariableService;
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
|
||||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
|
||||||
import static org.mockito.Mockito.*;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@SpringBootTest(classes = {
|
|
||||||
WorkflowEngineTest.TestConfig.class,
|
|
||||||
DefaultWorkflowEngine.class,
|
|
||||||
ObjectMapper.class
|
|
||||||
})
|
|
||||||
class WorkflowEngineTest {
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
static class TestConfig {
|
|
||||||
@Bean
|
|
||||||
Map<NodeTypeEnum, NodeExecutor> nodeExecutors() {
|
|
||||||
Map<NodeTypeEnum, NodeExecutor> executors = new HashMap<>();
|
|
||||||
StartNodeExecutor startExecutor = mock(StartNodeExecutor.class);
|
|
||||||
doNothing().when(startExecutor).execute(any(), any());
|
|
||||||
|
|
||||||
EndNodeExecutor endExecutor = mock(EndNodeExecutor.class);
|
|
||||||
doNothing().when(endExecutor).execute(any(), any());
|
|
||||||
|
|
||||||
TaskNodeExecutor taskExecutor = mock(TaskNodeExecutor.class);
|
|
||||||
doNothing().when(taskExecutor).execute(any(), any());
|
|
||||||
|
|
||||||
GatewayNodeExecutor gatewayExecutor = mock(GatewayNodeExecutor.class);
|
|
||||||
doNothing().when(gatewayExecutor).execute(any(), any());
|
|
||||||
|
|
||||||
executors.put(NodeTypeEnum.START, startExecutor);
|
|
||||||
executors.put(NodeTypeEnum.END, endExecutor);
|
|
||||||
executors.put(NodeTypeEnum.TASK, taskExecutor);
|
|
||||||
executors.put(NodeTypeEnum.GATEWAY, gatewayExecutor);
|
|
||||||
return executors;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
IWorkflowVariableService workflowVariableService() {
|
|
||||||
IWorkflowVariableService service = mock(IWorkflowVariableService.class);
|
|
||||||
doNothing().when(service).setVariable(any(), anyString(), any());
|
|
||||||
return service;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
IWorkflowLogService workflowLogService() {
|
|
||||||
return mock(IWorkflowLogService.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
DefaultWorkflowContext.Factory workflowContextFactory(
|
|
||||||
IWorkflowVariableService variableService,
|
|
||||||
IWorkflowLogService logService
|
|
||||||
) {
|
|
||||||
return new DefaultWorkflowContext.Factory(variableService, logService);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private WorkflowEngine workflowEngine;
|
|
||||||
|
|
||||||
@MockBean
|
|
||||||
private IWorkflowDefinitionService workflowDefinitionService;
|
|
||||||
|
|
||||||
@MockBean
|
|
||||||
private IWorkflowDefinitionRepository workflowDefinitionRepository;
|
|
||||||
|
|
||||||
@MockBean
|
|
||||||
private IWorkflowInstanceRepository workflowInstanceRepository;
|
|
||||||
|
|
||||||
@MockBean
|
|
||||||
private INodeInstanceRepository nodeInstanceRepository;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private ObjectMapper objectMapper;
|
|
||||||
|
|
||||||
private NodeInstance savedStartNode;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
void setUp() {
|
|
||||||
log.info("Setting up workflow engine test mocks...");
|
|
||||||
|
|
||||||
// Mock workflowDefinitionService
|
|
||||||
when(workflowDefinitionService.create(any())).thenAnswer(i -> {
|
|
||||||
WorkflowDefinitionDTO dto = i.getArgument(0);
|
|
||||||
dto.setId(1L);
|
|
||||||
log.info("Created workflow definition with ID: {}", dto.getId());
|
|
||||||
return dto;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Mock workflowDefinitionRepository
|
|
||||||
when(workflowDefinitionRepository.findByCodeAndDeletedFalse(anyString()))
|
|
||||||
.thenAnswer(i -> {
|
|
||||||
WorkflowDefinition definition = new WorkflowDefinition();
|
|
||||||
definition.setId(1L);
|
|
||||||
definition.setName("简单测试工作流");
|
|
||||||
definition.setCode("SIMPLE_TEST_WORKFLOW");
|
|
||||||
definition.setStatus(WorkflowStatusEnum.PUBLISHED);
|
|
||||||
definition.setNodeConfig(createSimpleWorkflow().getNodeConfig());
|
|
||||||
definition.setTransitionConfig(createSimpleWorkflow().getTransitionConfig());
|
|
||||||
log.info("Found workflow definition: code={}, status={}", definition.getCode(), definition.getStatus());
|
|
||||||
return definition;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Mock workflowInstanceRepository
|
|
||||||
when(workflowInstanceRepository.save(any())).thenAnswer(i -> {
|
|
||||||
WorkflowInstance instance = i.getArgument(0);
|
|
||||||
if (instance.getId() == null) {
|
|
||||||
instance.setId(1L);
|
|
||||||
}
|
|
||||||
log.info("Saved workflow instance: id={}, status={}", instance.getId(), instance.getStatus());
|
|
||||||
return instance;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Mock nodeInstanceRepository
|
|
||||||
when(nodeInstanceRepository.save(any())).thenAnswer(i -> {
|
|
||||||
NodeInstance node = i.getArgument(0);
|
|
||||||
if (node.getId() == null) {
|
|
||||||
node.setId(System.nanoTime());
|
|
||||||
}
|
|
||||||
savedStartNode = node;
|
|
||||||
|
|
||||||
// Create and set the workflow instance if it doesn't exist
|
|
||||||
if (node.getWorkflowInstance() == null) {
|
|
||||||
WorkflowInstance instance = new WorkflowInstance();
|
|
||||||
instance.setId(1L);
|
|
||||||
instance.setStatus(WorkflowStatusEnum.RUNNING);
|
|
||||||
node.setWorkflowInstance(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info("Saved node instance: id={}, type={}, status={}, workflowInstanceId={}",
|
|
||||||
node.getId(), node.getNodeType(), node.getStatus(), node.getWorkflowInstance().getId());
|
|
||||||
return node;
|
|
||||||
});
|
|
||||||
|
|
||||||
when(nodeInstanceRepository.findById(any())).thenAnswer(i -> {
|
|
||||||
if (savedStartNode != null && savedStartNode.getId().equals(i.getArgument(0))) {
|
|
||||||
log.info("Found node instance by id: {}, type={}, status={}",
|
|
||||||
savedStartNode.getId(), savedStartNode.getNodeType(), savedStartNode.getStatus());
|
|
||||||
return Optional.of(savedStartNode);
|
|
||||||
}
|
|
||||||
log.warn("Node instance not found with id: {}", (Object)i.getArgument(0));
|
|
||||||
return Optional.empty();
|
|
||||||
});
|
|
||||||
|
|
||||||
when(nodeInstanceRepository.findByWorkflowInstanceIdOrderByCreateTime(any()))
|
|
||||||
.thenAnswer(i -> {
|
|
||||||
WorkflowInstance instance = new WorkflowInstance();
|
|
||||||
instance.setId(1L);
|
|
||||||
instance.setStatus(WorkflowStatusEnum.RUNNING);
|
|
||||||
|
|
||||||
List<NodeInstance> nodes = List.of(
|
|
||||||
createNodeInstance(NodeTypeEnum.START, NodeStatusEnum.COMPLETED),
|
|
||||||
createNodeInstance(NodeTypeEnum.TASK, NodeStatusEnum.COMPLETED),
|
|
||||||
createNodeInstance(NodeTypeEnum.END, NodeStatusEnum.COMPLETED)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Set workflow instance for each node
|
|
||||||
nodes.forEach(node -> node.setWorkflowInstance(instance));
|
|
||||||
|
|
||||||
log.info("Found {} nodes for workflow instance id={}", nodes.size(), i.getArgument(0));
|
|
||||||
nodes.forEach(node -> log.info("Node: type={}, status={}", node.getNodeType(), node.getStatus()));
|
|
||||||
|
|
||||||
return nodes;
|
|
||||||
});
|
|
||||||
|
|
||||||
log.info("Test setup completed");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testSimpleWorkflow() {
|
|
||||||
log.info("Starting simple workflow test");
|
|
||||||
|
|
||||||
// 1. 创建工作流定义
|
|
||||||
WorkflowDefinitionDTO definition = createSimpleWorkflow();
|
|
||||||
log.info("Created workflow definition: name={}, code={}", definition.getName(), definition.getCode());
|
|
||||||
|
|
||||||
// 2. 启动工作流实例
|
|
||||||
Map<String, Object> variables = new HashMap<>();
|
|
||||||
variables.put("input", "test");
|
|
||||||
log.info("Starting workflow with variables: {}", variables);
|
|
||||||
|
|
||||||
WorkflowInstance instance = workflowEngine.startWorkflow(
|
|
||||||
definition.getCode(),
|
|
||||||
"TEST-" + System.currentTimeMillis(),
|
|
||||||
variables
|
|
||||||
);
|
|
||||||
|
|
||||||
// 3. 验证工作流实例状态
|
|
||||||
assertNotNull(instance);
|
|
||||||
assertEquals(WorkflowStatusEnum.RUNNING, instance.getStatus());
|
|
||||||
log.info("Workflow instance started: id={}, status={}", instance.getId(), instance.getStatus());
|
|
||||||
|
|
||||||
// 4. 验证节点执行状态
|
|
||||||
List<NodeInstance> nodes = nodeInstanceRepository.findByWorkflowInstanceIdOrderByCreateTime(instance.getId());
|
|
||||||
assertEquals(3, nodes.size());
|
|
||||||
log.info("Found {} nodes in workflow instance", nodes.size());
|
|
||||||
|
|
||||||
// 验证开始节点
|
|
||||||
NodeInstance startNode = nodes.get(0);
|
|
||||||
assertEquals(NodeTypeEnum.START, startNode.getNodeType());
|
|
||||||
assertEquals(NodeStatusEnum.COMPLETED, startNode.getStatus());
|
|
||||||
log.info("Start node validation passed: id={}, status={}", startNode.getId(), startNode.getStatus());
|
|
||||||
|
|
||||||
// 验证Shell节点
|
|
||||||
NodeInstance shellNode = nodes.get(1);
|
|
||||||
assertEquals(NodeTypeEnum.TASK, shellNode.getNodeType());
|
|
||||||
assertEquals(NodeStatusEnum.COMPLETED, shellNode.getStatus());
|
|
||||||
log.info("Shell node validation passed: id={}, status={}", shellNode.getId(), shellNode.getStatus());
|
|
||||||
|
|
||||||
// 验证结束节点
|
|
||||||
NodeInstance endNode = nodes.get(2);
|
|
||||||
assertEquals(NodeTypeEnum.END, endNode.getNodeType());
|
|
||||||
assertEquals(NodeStatusEnum.COMPLETED, endNode.getStatus());
|
|
||||||
log.info("End node validation passed: id={}, status={}", endNode.getId(), endNode.getStatus());
|
|
||||||
|
|
||||||
log.info("Simple workflow test completed successfully");
|
|
||||||
}
|
|
||||||
|
|
||||||
private WorkflowDefinitionDTO createSimpleWorkflow() {
|
|
||||||
WorkflowDefinitionDTO dto = new WorkflowDefinitionDTO();
|
|
||||||
dto.setId(1L);
|
|
||||||
dto.setName("简单测试工作流");
|
|
||||||
dto.setCode("SIMPLE_TEST_WORKFLOW");
|
|
||||||
dto.setStatus(WorkflowStatusEnum.PUBLISHED);
|
|
||||||
|
|
||||||
// 节点配置
|
|
||||||
String nodeConfig = """
|
|
||||||
{
|
|
||||||
"nodes": [
|
|
||||||
{
|
|
||||||
"id": "start",
|
|
||||||
"name": "开始",
|
|
||||||
"type": "START"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "shell",
|
|
||||||
"name": "Shell任务",
|
|
||||||
"type": "TASK",
|
|
||||||
"config": {
|
|
||||||
"type": "SHELL",
|
|
||||||
"script": "echo 'Hello World'",
|
|
||||||
"workingDirectory": "/tmp",
|
|
||||||
"successExitCode": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "end",
|
|
||||||
"name": "结束",
|
|
||||||
"type": "END"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
""";
|
|
||||||
dto.setNodeConfig(nodeConfig);
|
|
||||||
|
|
||||||
// 流转配置
|
|
||||||
String transitionConfig = """
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"sourceNodeId": "start",
|
|
||||||
"targetNodeId": "shell",
|
|
||||||
"condition": null,
|
|
||||||
"priority": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"sourceNodeId": "shell",
|
|
||||||
"targetNodeId": "end",
|
|
||||||
"condition": null,
|
|
||||||
"priority": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
""";
|
|
||||||
dto.setTransitionConfig(transitionConfig);
|
|
||||||
|
|
||||||
return dto;
|
|
||||||
}
|
|
||||||
|
|
||||||
private NodeInstance createNodeInstance(NodeTypeEnum type, NodeStatusEnum status) {
|
|
||||||
NodeInstance node = new NodeInstance();
|
|
||||||
node.setId(System.nanoTime());
|
|
||||||
node.setNodeType(type);
|
|
||||||
node.setStatus(status);
|
|
||||||
|
|
||||||
// Create and set a workflow instance
|
|
||||||
WorkflowInstance instance = new WorkflowInstance();
|
|
||||||
instance.setId(1L);
|
|
||||||
instance.setStatus(WorkflowStatusEnum.RUNNING);
|
|
||||||
node.setWorkflowInstance(instance);
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,138 +0,0 @@
|
|||||||
package com.qqchen.deploy.backend.workflow.repository;
|
|
||||||
|
|
||||||
import com.qqchen.deploy.backend.workflow.entity.NodeDefinition;
|
|
||||||
import com.qqchen.deploy.backend.workflow.entity.WorkflowDefinition;
|
|
||||||
import com.qqchen.deploy.backend.workflow.enums.NodeTypeEnum;
|
|
||||||
import com.qqchen.deploy.backend.workflow.enums.WorkflowStatusEnum;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
|
||||||
import org.springframework.test.context.ActiveProfiles;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
|
|
||||||
@DataJpaTest
|
|
||||||
@ActiveProfiles("test")
|
|
||||||
class NodeDefinitionRepositoryTest {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private INodeDefinitionRepository nodeDefinitionRepository;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private IWorkflowDefinitionRepository workflowDefinitionRepository;
|
|
||||||
|
|
||||||
private WorkflowDefinition workflowDefinition;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
void setUp() {
|
|
||||||
// 创建工作流定义
|
|
||||||
workflowDefinition = new WorkflowDefinition();
|
|
||||||
workflowDefinition.setCode("TEST-WF");
|
|
||||||
workflowDefinition.setName("Test Workflow");
|
|
||||||
workflowDefinition.setStatus(WorkflowStatusEnum.DRAFT);
|
|
||||||
workflowDefinition.setVersion(1);
|
|
||||||
workflowDefinition.setEnabled(true);
|
|
||||||
workflowDefinition = workflowDefinitionRepository.save(workflowDefinition);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void findByWorkflowDefinitionId_ShouldReturnNodesOrderedByOrderNum() {
|
|
||||||
// Given
|
|
||||||
NodeDefinition node1 = createNodeDefinition("NODE-001", "Node 1", NodeTypeEnum.START, 1);
|
|
||||||
NodeDefinition node2 = createNodeDefinition("NODE-002", "Node 2", NodeTypeEnum.TASK, 2);
|
|
||||||
NodeDefinition node3 = createNodeDefinition("NODE-003", "Node 3", NodeTypeEnum.END, 3);
|
|
||||||
|
|
||||||
nodeDefinitionRepository.save(node1);
|
|
||||||
nodeDefinitionRepository.save(node2);
|
|
||||||
nodeDefinitionRepository.save(node3);
|
|
||||||
|
|
||||||
// When
|
|
||||||
List<NodeDefinition> results = nodeDefinitionRepository.findByWorkflowDefinitionId(workflowDefinition.getId());
|
|
||||||
|
|
||||||
// Then
|
|
||||||
assertThat(results).hasSize(3);
|
|
||||||
assertThat(results.get(0).getOrderNum()).isEqualTo(1);
|
|
||||||
assertThat(results.get(1).getOrderNum()).isEqualTo(2);
|
|
||||||
assertThat(results.get(2).getOrderNum()).isEqualTo(3);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void findByWorkflowDefinitionIdAndType_ShouldReturnNodesWithSpecificType() {
|
|
||||||
// Given
|
|
||||||
NodeDefinition startNode = createNodeDefinition("START-001", "Start Node", NodeTypeEnum.START, 1);
|
|
||||||
NodeDefinition taskNode1 = createNodeDefinition("TASK-001", "Task Node 1", NodeTypeEnum.TASK, 2);
|
|
||||||
NodeDefinition taskNode2 = createNodeDefinition("TASK-002", "Task Node 2", NodeTypeEnum.TASK, 3);
|
|
||||||
NodeDefinition endNode = createNodeDefinition("END-001", "End Node", NodeTypeEnum.END, 4);
|
|
||||||
|
|
||||||
nodeDefinitionRepository.save(startNode);
|
|
||||||
nodeDefinitionRepository.save(taskNode1);
|
|
||||||
nodeDefinitionRepository.save(taskNode2);
|
|
||||||
nodeDefinitionRepository.save(endNode);
|
|
||||||
|
|
||||||
// When
|
|
||||||
List<NodeDefinition> results = nodeDefinitionRepository.findByWorkflowDefinitionIdAndType(
|
|
||||||
workflowDefinition.getId(), NodeTypeEnum.TASK);
|
|
||||||
|
|
||||||
// Then
|
|
||||||
assertThat(results).hasSize(2);
|
|
||||||
assertThat(results).allMatch(node -> node.getType() == NodeTypeEnum.TASK);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void findByWorkflowDefinitionIdAndCode_ShouldReturnSpecificNode() {
|
|
||||||
// Given
|
|
||||||
NodeDefinition node = createNodeDefinition("NODE-001", "Test Node", NodeTypeEnum.TASK, 1);
|
|
||||||
nodeDefinitionRepository.save(node);
|
|
||||||
|
|
||||||
// When
|
|
||||||
NodeDefinition result = nodeDefinitionRepository.findByWorkflowDefinitionIdAndCodeAndDeletedFalse(
|
|
||||||
workflowDefinition.getId(), "NODE-001");
|
|
||||||
|
|
||||||
// Then
|
|
||||||
assertThat(result).isNotNull();
|
|
||||||
assertThat(result.getCode()).isEqualTo("NODE-001");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void existsByWorkflowDefinitionIdAndCode_ShouldReturnTrue_WhenNodeExists() {
|
|
||||||
// Given
|
|
||||||
NodeDefinition node = createNodeDefinition("NODE-001", "Test Node", NodeTypeEnum.TASK, 1);
|
|
||||||
nodeDefinitionRepository.save(node);
|
|
||||||
|
|
||||||
// When
|
|
||||||
boolean exists = nodeDefinitionRepository.existsByWorkflowDefinitionIdAndCodeAndDeletedFalse(
|
|
||||||
workflowDefinition.getId(), "NODE-001");
|
|
||||||
|
|
||||||
// Then
|
|
||||||
assertThat(exists).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void deleteByWorkflowDefinitionId_ShouldMarkNodesAsDeleted() {
|
|
||||||
// Given
|
|
||||||
NodeDefinition node1 = createNodeDefinition("NODE-001", "Node 1", NodeTypeEnum.START, 1);
|
|
||||||
NodeDefinition node2 = createNodeDefinition("NODE-002", "Node 2", NodeTypeEnum.TASK, 2);
|
|
||||||
nodeDefinitionRepository.save(node1);
|
|
||||||
nodeDefinitionRepository.save(node2);
|
|
||||||
|
|
||||||
// When
|
|
||||||
nodeDefinitionRepository.deleteByWorkflowDefinitionId(workflowDefinition.getId());
|
|
||||||
|
|
||||||
// Then
|
|
||||||
List<NodeDefinition> remainingNodes = nodeDefinitionRepository.findByWorkflowDefinitionId(workflowDefinition.getId());
|
|
||||||
assertThat(remainingNodes).isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
private NodeDefinition createNodeDefinition(String code, String name, NodeTypeEnum type, Integer orderNum) {
|
|
||||||
NodeDefinition node = new NodeDefinition();
|
|
||||||
node.setCode(code);
|
|
||||||
node.setName(name);
|
|
||||||
node.setType(type);
|
|
||||||
node.setOrderNum(orderNum);
|
|
||||||
node.setWorkflowDefinition(workflowDefinition);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,131 +0,0 @@
|
|||||||
package com.qqchen.deploy.backend.workflow.repository;
|
|
||||||
|
|
||||||
import com.qqchen.deploy.backend.workflow.entity.WorkflowDefinition;
|
|
||||||
import com.qqchen.deploy.backend.workflow.enums.WorkflowStatusEnum;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
|
||||||
import org.springframework.test.context.ActiveProfiles;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
|
|
||||||
@DataJpaTest
|
|
||||||
@ActiveProfiles("test")
|
|
||||||
class WorkflowDefinitionRepositoryTest {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private IWorkflowDefinitionRepository workflowDefinitionRepository;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void findLatestByCode_ShouldReturnLatestVersion() {
|
|
||||||
// Given
|
|
||||||
WorkflowDefinition def1 = createWorkflowDefinition("TEST-001", "Test Workflow 1", 1);
|
|
||||||
WorkflowDefinition def2 = createWorkflowDefinition("TEST-001", "Test Workflow 1", 2);
|
|
||||||
workflowDefinitionRepository.save(def1);
|
|
||||||
workflowDefinitionRepository.save(def2);
|
|
||||||
|
|
||||||
// When
|
|
||||||
Optional<WorkflowDefinition> result = workflowDefinitionRepository.findLatestByCode("TEST-001");
|
|
||||||
|
|
||||||
// Then
|
|
||||||
assertThat(result).isPresent();
|
|
||||||
assertThat(result.get().getVersion()).isEqualTo(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void findByCodeAndVersion_ShouldReturnSpecificVersion() {
|
|
||||||
// Given
|
|
||||||
WorkflowDefinition def1 = createWorkflowDefinition("TEST-002", "Test Workflow 2", 1);
|
|
||||||
WorkflowDefinition def2 = createWorkflowDefinition("TEST-002", "Test Workflow 2", 2);
|
|
||||||
workflowDefinitionRepository.save(def1);
|
|
||||||
workflowDefinitionRepository.save(def2);
|
|
||||||
|
|
||||||
// When
|
|
||||||
Optional<WorkflowDefinition> result = workflowDefinitionRepository.findByCodeAndVersionAndDeletedFalse("TEST-002", 1);
|
|
||||||
|
|
||||||
// Then
|
|
||||||
assertThat(result).isPresent();
|
|
||||||
assertThat(result.get().getVersion()).isEqualTo(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void findAllVersionsByCode_ShouldReturnAllVersionsOrderedByVersionDesc() {
|
|
||||||
// Given
|
|
||||||
WorkflowDefinition def1 = createWorkflowDefinition("TEST-003", "Test Workflow 3", 1);
|
|
||||||
WorkflowDefinition def2 = createWorkflowDefinition("TEST-003", "Test Workflow 3", 2);
|
|
||||||
WorkflowDefinition def3 = createWorkflowDefinition("TEST-003", "Test Workflow 3", 3);
|
|
||||||
workflowDefinitionRepository.save(def1);
|
|
||||||
workflowDefinitionRepository.save(def2);
|
|
||||||
workflowDefinitionRepository.save(def3);
|
|
||||||
|
|
||||||
// When
|
|
||||||
List<WorkflowDefinition> results = workflowDefinitionRepository.findAllVersionsByCode("TEST-003");
|
|
||||||
|
|
||||||
// Then
|
|
||||||
assertThat(results).hasSize(3);
|
|
||||||
assertThat(results.get(0).getVersion()).isEqualTo(3);
|
|
||||||
assertThat(results.get(1).getVersion()).isEqualTo(2);
|
|
||||||
assertThat(results.get(2).getVersion()).isEqualTo(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void findByStatus_ShouldReturnWorkflowsWithSpecificStatus() {
|
|
||||||
// Given
|
|
||||||
WorkflowDefinition def1 = createWorkflowDefinition("TEST-004", "Test Workflow 4", 1);
|
|
||||||
def1.setStatus(WorkflowStatusEnum.PUBLISHED);
|
|
||||||
WorkflowDefinition def2 = createWorkflowDefinition("TEST-005", "Test Workflow 5", 1);
|
|
||||||
def2.setStatus(WorkflowStatusEnum.DRAFT);
|
|
||||||
workflowDefinitionRepository.save(def1);
|
|
||||||
workflowDefinitionRepository.save(def2);
|
|
||||||
|
|
||||||
// When
|
|
||||||
List<WorkflowDefinition> results = workflowDefinitionRepository.findByStatusAndDeletedFalse(WorkflowStatusEnum.PUBLISHED);
|
|
||||||
|
|
||||||
// Then
|
|
||||||
assertThat(results).hasSize(1);
|
|
||||||
assertThat(results.get(0).getStatus()).isEqualTo(WorkflowStatusEnum.PUBLISHED);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void existsByCode_ShouldReturnTrueWhenCodeExists() {
|
|
||||||
// Given
|
|
||||||
WorkflowDefinition def = createWorkflowDefinition("TEST-006", "Test Workflow 6", 1);
|
|
||||||
workflowDefinitionRepository.save(def);
|
|
||||||
|
|
||||||
// When
|
|
||||||
boolean exists = workflowDefinitionRepository.existsByCodeAndDeletedFalse("TEST-006");
|
|
||||||
|
|
||||||
// Then
|
|
||||||
assertThat(exists).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void findLatestVersionByCode_ShouldReturnHighestVersion() {
|
|
||||||
// Given
|
|
||||||
WorkflowDefinition def1 = createWorkflowDefinition("TEST-007", "Test Workflow 7", 1);
|
|
||||||
WorkflowDefinition def2 = createWorkflowDefinition("TEST-007", "Test Workflow 7", 2);
|
|
||||||
WorkflowDefinition def3 = createWorkflowDefinition("TEST-007", "Test Workflow 7", 3);
|
|
||||||
workflowDefinitionRepository.save(def1);
|
|
||||||
workflowDefinitionRepository.save(def2);
|
|
||||||
workflowDefinitionRepository.save(def3);
|
|
||||||
|
|
||||||
// When
|
|
||||||
Integer latestVersion = workflowDefinitionRepository.findLatestVersionByCode("TEST-007");
|
|
||||||
|
|
||||||
// Then
|
|
||||||
assertThat(latestVersion).isEqualTo(3);
|
|
||||||
}
|
|
||||||
|
|
||||||
private WorkflowDefinition createWorkflowDefinition(String code, String name, Integer version) {
|
|
||||||
WorkflowDefinition def = new WorkflowDefinition();
|
|
||||||
def.setCode(code);
|
|
||||||
def.setName(name);
|
|
||||||
def.setVersion(version);
|
|
||||||
def.setStatus(WorkflowStatusEnum.DRAFT);
|
|
||||||
def.setEnabled(true);
|
|
||||||
return def;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,168 +0,0 @@
|
|||||||
package com.qqchen.deploy.backend.workflow.service;
|
|
||||||
|
|
||||||
import com.qqchen.deploy.backend.framework.exception.BusinessException;
|
|
||||||
import com.qqchen.deploy.backend.workflow.converter.WorkflowDefinitionConverter;
|
|
||||||
import com.qqchen.deploy.backend.workflow.dto.WorkflowDefinitionDTO;
|
|
||||||
import com.qqchen.deploy.backend.workflow.entity.WorkflowDefinition;
|
|
||||||
import com.qqchen.deploy.backend.workflow.enums.WorkflowStatusEnum;
|
|
||||||
import com.qqchen.deploy.backend.workflow.repository.INodeDefinitionRepository;
|
|
||||||
import com.qqchen.deploy.backend.workflow.repository.IWorkflowDefinitionRepository;
|
|
||||||
import com.qqchen.deploy.backend.workflow.service.impl.WorkflowDefinitionServiceImpl;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
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 java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
|
||||||
import static org.mockito.Mockito.*;
|
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
|
||||||
class WorkflowDefinitionServiceTest {
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private IWorkflowDefinitionRepository workflowDefinitionRepository;
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private INodeDefinitionRepository nodeDefinitionRepository;
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private WorkflowDefinitionConverter workflowDefinitionConverter;
|
|
||||||
|
|
||||||
@InjectMocks
|
|
||||||
private WorkflowDefinitionServiceImpl workflowDefinitionService;
|
|
||||||
|
|
||||||
private WorkflowDefinition mockWorkflowDefinition;
|
|
||||||
private WorkflowDefinitionDTO mockWorkflowDefinitionDTO;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
void setUp() {
|
|
||||||
mockWorkflowDefinition = new WorkflowDefinition();
|
|
||||||
mockWorkflowDefinition.setId(1L);
|
|
||||||
mockWorkflowDefinition.setCode("TEST-001");
|
|
||||||
mockWorkflowDefinition.setName("Test Workflow");
|
|
||||||
mockWorkflowDefinition.setVersion(1);
|
|
||||||
mockWorkflowDefinition.setStatus(WorkflowStatusEnum.DRAFT);
|
|
||||||
mockWorkflowDefinition.setEnabled(true);
|
|
||||||
|
|
||||||
mockWorkflowDefinitionDTO = new WorkflowDefinitionDTO();
|
|
||||||
mockWorkflowDefinitionDTO.setId(1L);
|
|
||||||
mockWorkflowDefinitionDTO.setCode("TEST-001");
|
|
||||||
mockWorkflowDefinitionDTO.setName("Test Workflow");
|
|
||||||
mockWorkflowDefinitionDTO.setVersion(1);
|
|
||||||
mockWorkflowDefinitionDTO.setStatus(WorkflowStatusEnum.DRAFT);
|
|
||||||
mockWorkflowDefinitionDTO.setEnabled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void create_ShouldCreateNewWorkflowDefinition() {
|
|
||||||
// Given
|
|
||||||
when(workflowDefinitionRepository.existsByCodeAndDeletedFalse(anyString())).thenReturn(false);
|
|
||||||
when(workflowDefinitionRepository.save(any(WorkflowDefinition.class))).thenReturn(mockWorkflowDefinition);
|
|
||||||
when(workflowDefinitionConverter.toEntity(any(WorkflowDefinitionDTO.class))).thenReturn(mockWorkflowDefinition);
|
|
||||||
when(workflowDefinitionConverter.toDto(any(WorkflowDefinition.class))).thenReturn(mockWorkflowDefinitionDTO);
|
|
||||||
|
|
||||||
// When
|
|
||||||
WorkflowDefinitionDTO result = workflowDefinitionService.create(mockWorkflowDefinitionDTO);
|
|
||||||
|
|
||||||
// Then
|
|
||||||
assertThat(result).isNotNull();
|
|
||||||
assertThat(result.getStatus()).isEqualTo(WorkflowStatusEnum.DRAFT);
|
|
||||||
assertThat(result.getVersion()).isEqualTo(1);
|
|
||||||
verify(workflowDefinitionRepository).save(any(WorkflowDefinition.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void create_ShouldThrowException_WhenCodeExists() {
|
|
||||||
// Given
|
|
||||||
when(workflowDefinitionRepository.existsByCodeAndDeletedFalse(anyString())).thenReturn(true);
|
|
||||||
|
|
||||||
// When/Then
|
|
||||||
assertThatThrownBy(() -> workflowDefinitionService.create(mockWorkflowDefinitionDTO))
|
|
||||||
.isInstanceOf(BusinessException.class)
|
|
||||||
.hasMessage("工作流编码已存在");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void publish_ShouldPublishWorkflowDefinition() {
|
|
||||||
// Given
|
|
||||||
mockWorkflowDefinition.setStatus(WorkflowStatusEnum.DRAFT);
|
|
||||||
when(workflowDefinitionRepository.findById(anyLong())).thenReturn(Optional.of(mockWorkflowDefinition));
|
|
||||||
when(workflowDefinitionRepository.save(any(WorkflowDefinition.class))).thenReturn(mockWorkflowDefinition);
|
|
||||||
when(workflowDefinitionConverter.toDto(any(WorkflowDefinition.class))).thenReturn(mockWorkflowDefinitionDTO);
|
|
||||||
|
|
||||||
// When
|
|
||||||
WorkflowDefinitionDTO result = workflowDefinitionService.publish(1L);
|
|
||||||
|
|
||||||
// Then
|
|
||||||
assertThat(result).isNotNull();
|
|
||||||
assertThat(result.getStatus()).isEqualTo(WorkflowStatusEnum.PUBLISHED);
|
|
||||||
verify(workflowDefinitionRepository).save(any(WorkflowDefinition.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void publish_ShouldThrowException_WhenNotDraft() {
|
|
||||||
// Given
|
|
||||||
mockWorkflowDefinition.setStatus(WorkflowStatusEnum.PUBLISHED);
|
|
||||||
when(workflowDefinitionRepository.findById(anyLong())).thenReturn(Optional.of(mockWorkflowDefinition));
|
|
||||||
|
|
||||||
// When/Then
|
|
||||||
assertThatThrownBy(() -> workflowDefinitionService.publish(1L))
|
|
||||||
.isInstanceOf(BusinessException.class)
|
|
||||||
.hasMessage("只有草稿状态的工作流定义可以发布");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void createNewVersion_ShouldCreateNewVersion() {
|
|
||||||
// Given
|
|
||||||
when(workflowDefinitionRepository.findById(anyLong())).thenReturn(Optional.of(mockWorkflowDefinition));
|
|
||||||
when(workflowDefinitionRepository.findLatestVersionByCode(anyString())).thenReturn(1);
|
|
||||||
when(workflowDefinitionRepository.save(any(WorkflowDefinition.class))).thenReturn(mockWorkflowDefinition);
|
|
||||||
when(workflowDefinitionConverter.toDto(any(WorkflowDefinition.class))).thenReturn(mockWorkflowDefinitionDTO);
|
|
||||||
|
|
||||||
// When
|
|
||||||
WorkflowDefinitionDTO result = workflowDefinitionService.createNewVersion(1L);
|
|
||||||
|
|
||||||
// Then
|
|
||||||
assertThat(result).isNotNull();
|
|
||||||
assertThat(result.getStatus()).isEqualTo(WorkflowStatusEnum.DRAFT);
|
|
||||||
assertThat(result.getVersion()).isEqualTo(2);
|
|
||||||
verify(workflowDefinitionRepository).save(any(WorkflowDefinition.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void findAllVersions_ShouldReturnAllVersions() {
|
|
||||||
// Given
|
|
||||||
WorkflowDefinition version1 = createWorkflowDefinition(1);
|
|
||||||
WorkflowDefinition version2 = createWorkflowDefinition(2);
|
|
||||||
List<WorkflowDefinition> versions = Arrays.asList(version2, version1);
|
|
||||||
|
|
||||||
when(workflowDefinitionRepository.findAllVersionsByCode(anyString())).thenReturn(versions);
|
|
||||||
when(workflowDefinitionConverter.toDto(any(WorkflowDefinition.class))).thenReturn(mockWorkflowDefinitionDTO);
|
|
||||||
|
|
||||||
// When
|
|
||||||
List<WorkflowDefinitionDTO> results = workflowDefinitionService.findAllVersions("TEST-001");
|
|
||||||
|
|
||||||
// Then
|
|
||||||
assertThat(results).hasSize(2);
|
|
||||||
verify(workflowDefinitionRepository).findAllVersionsByCode("TEST-001");
|
|
||||||
}
|
|
||||||
|
|
||||||
private WorkflowDefinition createWorkflowDefinition(int version) {
|
|
||||||
WorkflowDefinition def = new WorkflowDefinition();
|
|
||||||
def.setId((long) version);
|
|
||||||
def.setCode("TEST-001");
|
|
||||||
def.setName("Test Workflow");
|
|
||||||
def.setVersion(version);
|
|
||||||
def.setStatus(WorkflowStatusEnum.DRAFT);
|
|
||||||
def.setEnabled(true);
|
|
||||||
return def;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user