Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
e6f51717a2
|
@ -272,9 +272,9 @@
|
|||
|
||||
<!-- swagger3 解析 -->
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>io.swagger.parser.v3</groupId>-->
|
||||
<!--<artifactId>swagger-parser</artifactId>-->
|
||||
<!--<version>2.0.24</version>-->
|
||||
<!--<groupId>io.swagger.parser.v3</groupId>-->
|
||||
<!--<artifactId>swagger-parser</artifactId>-->
|
||||
<!--<version>2.0.24</version>-->
|
||||
<!--</dependency>-->
|
||||
|
||||
<!-- 执行 js 代码依赖 -->
|
||||
|
@ -373,6 +373,12 @@
|
|||
<artifactId>httpclient</artifactId>
|
||||
<version>4.5.6</version>
|
||||
</dependency>
|
||||
<!-- 反射工具包 -->
|
||||
<dependency>
|
||||
<groupId>net.oneandone.reflections8</groupId>
|
||||
<artifactId>reflections8</artifactId>
|
||||
<version>0.11.7</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -1,16 +1,11 @@
|
|||
package io.metersphere.api.dto.definition;
|
||||
|
||||
import io.metersphere.base.domain.ApiModule;
|
||||
import io.metersphere.track.dto.TreeNodeDTO;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class ApiModuleDTO extends ApiModule {
|
||||
|
||||
private String label;
|
||||
private List<ApiModuleDTO> children;
|
||||
|
||||
public class ApiModuleDTO extends TreeNodeDTO<ApiModuleDTO> {
|
||||
private String protocol;
|
||||
}
|
||||
|
|
|
@ -51,6 +51,9 @@ public class MsDubboSampler extends MsTestElement {
|
|||
@JSONField(ordinal = 59)
|
||||
private List<KeyValue> attachmentArgs;
|
||||
|
||||
@JSONField(ordinal = 60)
|
||||
private Object requestResult;
|
||||
|
||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
||||
if (!this.isEnable()) {
|
||||
return;
|
||||
|
|
|
@ -85,6 +85,9 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
|||
@JSONField(ordinal = 24)
|
||||
private List<KeyValue> arguments;
|
||||
|
||||
@JSONField(ordinal = 25)
|
||||
private Object requestResult;
|
||||
|
||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
||||
if (!this.isEnable()) {
|
||||
return;
|
||||
|
|
|
@ -38,6 +38,8 @@ public class MsJDBCSampler extends MsTestElement {
|
|||
private List<KeyValue> variables;
|
||||
@JSONField(ordinal = 16)
|
||||
private String environmentId;
|
||||
@JSONField(ordinal = 17)
|
||||
private Object requestResult;
|
||||
|
||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
||||
if (!this.isEnable()) {
|
||||
|
|
|
@ -48,6 +48,8 @@ public class MsTCPSampler extends MsTestElement {
|
|||
private String password = "";
|
||||
@JSONField(ordinal = 23)
|
||||
private String request;
|
||||
@JSONField(ordinal = 24)
|
||||
private Object requestResult;
|
||||
|
||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
||||
if (!this.isEnable()) {
|
||||
|
|
|
@ -11,10 +11,12 @@ import io.metersphere.base.domain.ApiModuleExample;
|
|||
import io.metersphere.base.mapper.ApiDefinitionMapper;
|
||||
import io.metersphere.base.mapper.ApiModuleMapper;
|
||||
import io.metersphere.base.mapper.ext.ExtApiDefinitionMapper;
|
||||
import io.metersphere.base.mapper.ext.ExtApiModuleMapper;
|
||||
import io.metersphere.commons.constants.TestCaseConstants;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.BeanUtils;
|
||||
|
||||
import io.metersphere.i18n.Translator;
|
||||
import io.metersphere.service.NodeTreeService;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.ibatis.session.ExecutorType;
|
||||
import org.apache.ibatis.session.SqlSession;
|
||||
|
@ -28,11 +30,13 @@ import java.util.stream.Collectors;
|
|||
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class ApiModuleService {
|
||||
public class ApiModuleService extends NodeTreeService<ApiModuleDTO> {
|
||||
|
||||
@Resource
|
||||
ApiModuleMapper apiModuleMapper;
|
||||
@Resource
|
||||
ExtApiModuleMapper extApiModuleMapper;
|
||||
@Resource
|
||||
private ApiDefinitionMapper apiDefinitionMapper;
|
||||
@Resource
|
||||
private ExtApiDefinitionMapper extApiDefinitionMapper;
|
||||
|
@ -41,61 +45,10 @@ public class ApiModuleService {
|
|||
SqlSessionFactory sqlSessionFactory;
|
||||
|
||||
public List<ApiModuleDTO> getNodeTreeByProjectId(String projectId, String protocol) {
|
||||
ApiModuleExample apiDefinitionNodeExample = new ApiModuleExample();
|
||||
apiDefinitionNodeExample.createCriteria().andProjectIdEqualTo(projectId).andProtocolEqualTo(protocol);
|
||||
apiDefinitionNodeExample.setOrderByClause("create_time asc");
|
||||
List<ApiModule> nodes = apiModuleMapper.selectByExample(apiDefinitionNodeExample);
|
||||
return getNodeTrees(nodes);
|
||||
List<ApiModuleDTO> apiModules = extApiModuleMapper.getNodeTreeByProjectId(projectId, protocol);
|
||||
return getNodeTrees(apiModules);
|
||||
}
|
||||
|
||||
public List<ApiModuleDTO> getNodeTrees(List<ApiModule> nodes) {
|
||||
|
||||
List<ApiModuleDTO> nodeTreeList = new ArrayList<>();
|
||||
Map<Integer, List<ApiModule>> nodeLevelMap = new HashMap<>();
|
||||
nodes.forEach(node -> {
|
||||
Integer level = node.getLevel();
|
||||
if (nodeLevelMap.containsKey(level)) {
|
||||
nodeLevelMap.get(level).add(node);
|
||||
} else {
|
||||
List<ApiModule> apiModules = new ArrayList<>();
|
||||
apiModules.add(node);
|
||||
nodeLevelMap.put(node.getLevel(), apiModules);
|
||||
}
|
||||
});
|
||||
List<ApiModule> rootNodes = Optional.ofNullable(nodeLevelMap.get(1)).orElse(new ArrayList<>());
|
||||
rootNodes.forEach(rootNode -> nodeTreeList.add(buildNodeTree(nodeLevelMap, rootNode)));
|
||||
return nodeTreeList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归构建节点树
|
||||
*
|
||||
* @param nodeLevelMap
|
||||
* @param rootNode
|
||||
* @return
|
||||
*/
|
||||
private ApiModuleDTO buildNodeTree(Map<Integer, List<ApiModule>> nodeLevelMap, ApiModule rootNode) {
|
||||
|
||||
ApiModuleDTO nodeTree = new ApiModuleDTO();
|
||||
BeanUtils.copyBean(nodeTree, rootNode);
|
||||
nodeTree.setLabel(rootNode.getName());
|
||||
|
||||
List<ApiModule> lowerNodes = nodeLevelMap.get(rootNode.getLevel() + 1);
|
||||
if (lowerNodes == null) {
|
||||
return nodeTree;
|
||||
}
|
||||
List<ApiModuleDTO> children = Optional.ofNullable(nodeTree.getChildren()).orElse(new ArrayList<>());
|
||||
lowerNodes.forEach(node -> {
|
||||
if (node.getParentId() != null && node.getParentId().equals(rootNode.getId())) {
|
||||
children.add(buildNodeTree(nodeLevelMap, node));
|
||||
nodeTree.setChildren(children);
|
||||
}
|
||||
});
|
||||
|
||||
return nodeTree;
|
||||
}
|
||||
|
||||
|
||||
public String addNode(ApiModule node) {
|
||||
validateNode(node);
|
||||
return addNodeWithoutValidate(node);
|
||||
|
|
|
@ -21,5 +21,7 @@ public class ApiModule implements Serializable {
|
|||
|
||||
private Long updateTime;
|
||||
|
||||
private Double pos;
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
|
@ -633,6 +633,66 @@ public class ApiModuleExample {
|
|||
addCriterion("update_time not between", value1, value2, "updateTime");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andPosIsNull() {
|
||||
addCriterion("pos is null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andPosIsNotNull() {
|
||||
addCriterion("pos is not null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andPosEqualTo(Double value) {
|
||||
addCriterion("pos =", value, "pos");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andPosNotEqualTo(Double value) {
|
||||
addCriterion("pos <>", value, "pos");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andPosGreaterThan(Double value) {
|
||||
addCriterion("pos >", value, "pos");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andPosGreaterThanOrEqualTo(Double value) {
|
||||
addCriterion("pos >=", value, "pos");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andPosLessThan(Double value) {
|
||||
addCriterion("pos <", value, "pos");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andPosLessThanOrEqualTo(Double value) {
|
||||
addCriterion("pos <=", value, "pos");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andPosIn(List<Double> values) {
|
||||
addCriterion("pos in", values, "pos");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andPosNotIn(List<Double> values) {
|
||||
addCriterion("pos not in", values, "pos");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andPosBetween(Double value1, Double value2) {
|
||||
addCriterion("pos between", value1, value2, "pos");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andPosNotBetween(Double value1, Double value2) {
|
||||
addCriterion("pos not between", value1, value2, "pos");
|
||||
return (Criteria) this;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Criteria extends GeneratedCriteria {
|
||||
|
|
|
@ -2,9 +2,8 @@ package io.metersphere.base.mapper;
|
|||
|
||||
import io.metersphere.base.domain.ApiModule;
|
||||
import io.metersphere.base.domain.ApiModuleExample;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
public interface ApiModuleMapper {
|
||||
long countByExample(ApiModuleExample example);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
<result column="level" jdbcType="INTEGER" property="level" />
|
||||
<result column="create_time" jdbcType="BIGINT" property="createTime" />
|
||||
<result column="update_time" jdbcType="BIGINT" property="updateTime" />
|
||||
<result column="pos" jdbcType="DOUBLE" property="pos" />
|
||||
</resultMap>
|
||||
<sql id="Example_Where_Clause">
|
||||
<where>
|
||||
|
@ -70,7 +71,7 @@
|
|||
</where>
|
||||
</sql>
|
||||
<sql id="Base_Column_List">
|
||||
id, project_id, `name`, protocol, parent_id, `level`, create_time, update_time
|
||||
id, project_id, `name`, protocol, parent_id, `level`, create_time, update_time, pos
|
||||
</sql>
|
||||
<select id="selectByExample" parameterType="io.metersphere.base.domain.ApiModuleExample" resultMap="BaseResultMap">
|
||||
select
|
||||
|
@ -105,10 +106,12 @@
|
|||
<insert id="insert" parameterType="io.metersphere.base.domain.ApiModule">
|
||||
insert into api_module (id, project_id, `name`,
|
||||
protocol, parent_id, `level`,
|
||||
create_time, update_time)
|
||||
create_time, update_time, pos
|
||||
)
|
||||
values (#{id,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
|
||||
#{protocol,jdbcType=VARCHAR}, #{parentId,jdbcType=VARCHAR}, #{level,jdbcType=INTEGER},
|
||||
#{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT})
|
||||
#{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, #{pos,jdbcType=DOUBLE}
|
||||
)
|
||||
</insert>
|
||||
<insert id="insertSelective" parameterType="io.metersphere.base.domain.ApiModule">
|
||||
insert into api_module
|
||||
|
@ -137,6 +140,9 @@
|
|||
<if test="updateTime != null">
|
||||
update_time,
|
||||
</if>
|
||||
<if test="pos != null">
|
||||
pos,
|
||||
</if>
|
||||
</trim>
|
||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||
<if test="id != null">
|
||||
|
@ -163,6 +169,9 @@
|
|||
<if test="updateTime != null">
|
||||
#{updateTime,jdbcType=BIGINT},
|
||||
</if>
|
||||
<if test="pos != null">
|
||||
#{pos,jdbcType=DOUBLE},
|
||||
</if>
|
||||
</trim>
|
||||
</insert>
|
||||
<select id="countByExample" parameterType="io.metersphere.base.domain.ApiModuleExample" resultType="java.lang.Long">
|
||||
|
@ -198,6 +207,9 @@
|
|||
<if test="record.updateTime != null">
|
||||
update_time = #{record.updateTime,jdbcType=BIGINT},
|
||||
</if>
|
||||
<if test="record.pos != null">
|
||||
pos = #{record.pos,jdbcType=DOUBLE},
|
||||
</if>
|
||||
</set>
|
||||
<if test="_parameter != null">
|
||||
<include refid="Update_By_Example_Where_Clause" />
|
||||
|
@ -212,7 +224,8 @@
|
|||
parent_id = #{record.parentId,jdbcType=VARCHAR},
|
||||
`level` = #{record.level,jdbcType=INTEGER},
|
||||
create_time = #{record.createTime,jdbcType=BIGINT},
|
||||
update_time = #{record.updateTime,jdbcType=BIGINT}
|
||||
update_time = #{record.updateTime,jdbcType=BIGINT},
|
||||
pos = #{record.pos,jdbcType=DOUBLE}
|
||||
<if test="_parameter != null">
|
||||
<include refid="Update_By_Example_Where_Clause" />
|
||||
</if>
|
||||
|
@ -241,6 +254,9 @@
|
|||
<if test="updateTime != null">
|
||||
update_time = #{updateTime,jdbcType=BIGINT},
|
||||
</if>
|
||||
<if test="pos != null">
|
||||
pos = #{pos,jdbcType=DOUBLE},
|
||||
</if>
|
||||
</set>
|
||||
where id = #{id,jdbcType=VARCHAR}
|
||||
</update>
|
||||
|
@ -252,7 +268,8 @@
|
|||
parent_id = #{parentId,jdbcType=VARCHAR},
|
||||
`level` = #{level,jdbcType=INTEGER},
|
||||
create_time = #{createTime,jdbcType=BIGINT},
|
||||
update_time = #{updateTime,jdbcType=BIGINT}
|
||||
update_time = #{updateTime,jdbcType=BIGINT},
|
||||
pos = #{pos,jdbcType=DOUBLE}
|
||||
where id = #{id,jdbcType=VARCHAR}
|
||||
</update>
|
||||
</mapper>
|
|
@ -1,5 +1,6 @@
|
|||
package io.metersphere.base.mapper.ext;
|
||||
|
||||
import io.metersphere.api.dto.definition.ApiModuleDTO;
|
||||
import io.metersphere.base.domain.ApiModule;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
|
@ -7,4 +8,5 @@ import java.util.List;
|
|||
|
||||
public interface ExtApiModuleMapper {
|
||||
int insertBatch(@Param("records") List<ApiModule> records);
|
||||
List<ApiModuleDTO> getNodeTreeByProjectId(@Param("projectId") String projectId, @Param("protocol") String protocol);
|
||||
}
|
|
@ -13,4 +13,12 @@
|
|||
#{emp.updateTime,jdbcType=BIGINT})
|
||||
</foreach>
|
||||
</insert>
|
||||
<select id="getNodeTreeByProjectId" resultType="io.metersphere.api.dto.definition.ApiModuleDTO">
|
||||
select
|
||||
<include refid="io.metersphere.base.mapper.ApiModuleMapper.Base_Column_List"/>
|
||||
from api_module
|
||||
where api_module.project_id = #{projectId}
|
||||
and api_module.protocol = #{protocol}
|
||||
order by create_time asc
|
||||
</select>
|
||||
</mapper>
|
|
@ -0,0 +1,17 @@
|
|||
package io.metersphere.base.mapper.ext;
|
||||
|
||||
import io.metersphere.track.dto.TestCaseNodeDTO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ExtTestCaseNodeMapper {
|
||||
|
||||
List<TestCaseNodeDTO> getNodeTreeByProjectId(@Param("projectId") String projectId);
|
||||
|
||||
List<TestCaseNodeDTO> getNodeTreeByProjectIds(@Param("projectIds") List<String> projectIds);
|
||||
|
||||
TestCaseNodeDTO get(String id);
|
||||
|
||||
void updatePos(String id, Double pos);
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="io.metersphere.base.mapper.ext.ExtTestCaseNodeMapper">
|
||||
<select id="getNodeTreeByProjectId" resultType="io.metersphere.track.dto.TestCaseNodeDTO">
|
||||
select
|
||||
<include refid="io.metersphere.base.mapper.TestCaseNodeMapper.Base_Column_List"/>
|
||||
from test_case_node
|
||||
where test_case_node.project_id = #{projectId}
|
||||
order by pos asc
|
||||
</select>
|
||||
<select id="getNodeTreeByProjectIds" resultType="io.metersphere.track.dto.TestCaseNodeDTO">
|
||||
select
|
||||
<include refid="io.metersphere.base.mapper.TestCaseNodeMapper.Base_Column_List"/>
|
||||
from test_case_node
|
||||
where test_case_node.project_id
|
||||
in
|
||||
<foreach collection="projectIds" item="projectId" index="index" open="(" close=")" separator=",">
|
||||
#{projectId}
|
||||
</foreach>
|
||||
</select>
|
||||
<select id="get" resultType="io.metersphere.track.dto.TestCaseNodeDTO">
|
||||
select
|
||||
<include refid="io.metersphere.base.mapper.TestCaseNodeMapper.Base_Column_List"/>
|
||||
from test_case_node
|
||||
where id = #{id}
|
||||
</select>
|
||||
<update id="updatePos">
|
||||
update test_case_node set pos = #{pos}
|
||||
where id = #{id}
|
||||
</update>
|
||||
</mapper>
|
|
@ -58,7 +58,8 @@ public abstract class AbstractEngine implements Engine {
|
|||
if (resourcePool == null) {
|
||||
MSException.throwException("Resource Pool is empty");
|
||||
}
|
||||
if (!ResourcePoolTypeEnum.NODE.name().equals(resourcePool.getType())) {
|
||||
if (!ResourcePoolTypeEnum.K8S.name().equals(resourcePool.getType())
|
||||
&& !ResourcePoolTypeEnum.NODE.name().equals(resourcePool.getType())) {
|
||||
MSException.throwException("Invalid Resource Pool type.");
|
||||
}
|
||||
this.resourceList = testResourceService.getResourcesByPoolId(resourcePool.getId());
|
||||
|
|
|
@ -2,6 +2,7 @@ package io.metersphere.performance.engine;
|
|||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import io.metersphere.Application;
|
||||
import io.metersphere.base.domain.FileContent;
|
||||
import io.metersphere.base.domain.FileMetadata;
|
||||
import io.metersphere.base.domain.LoadTestWithBLOBs;
|
||||
|
@ -16,17 +17,17 @@ import io.metersphere.performance.engine.docker.DockerTestEngine;
|
|||
import io.metersphere.performance.parse.EngineSourceParser;
|
||||
import io.metersphere.performance.parse.EngineSourceParserFactory;
|
||||
import io.metersphere.service.FileService;
|
||||
import io.metersphere.service.KubernetesTestEngine;
|
||||
import io.metersphere.service.TestResourcePoolService;
|
||||
import org.apache.commons.beanutils.ConstructorUtils;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.reflections8.Reflections;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
|
@ -34,6 +35,17 @@ public class EngineFactory {
|
|||
private static FileService fileService;
|
||||
private static TestResourcePoolService testResourcePoolService;
|
||||
private static KafkaProperties kafkaProperties;
|
||||
private static Class<? extends KubernetesTestEngine> kubernetesTestEngineClass;
|
||||
|
||||
static {
|
||||
Reflections reflections = new Reflections(Application.class.getPackage().getName());
|
||||
Set<Class<? extends KubernetesTestEngine>> implClass = reflections.getSubTypesOf(KubernetesTestEngine.class);
|
||||
for (Class<? extends KubernetesTestEngine> aClass : implClass) {
|
||||
kubernetesTestEngineClass = aClass;
|
||||
// 第一个
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static Engine createEngine(LoadTestWithBLOBs loadTest) {
|
||||
String resourcePoolId = loadTest.getTestResourcePoolId();
|
||||
|
@ -51,6 +63,14 @@ public class EngineFactory {
|
|||
if (type == ResourcePoolTypeEnum.NODE) {
|
||||
return new DockerTestEngine(loadTest);
|
||||
}
|
||||
if (type == ResourcePoolTypeEnum.K8S) {
|
||||
try {
|
||||
return ConstructorUtils.invokeConstructor(kubernetesTestEngineClass, loadTest);
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package io.metersphere.service;
|
||||
|
||||
import io.metersphere.performance.engine.Engine;
|
||||
|
||||
public interface KubernetesTestEngine extends Engine {
|
||||
}
|
|
@ -0,0 +1,238 @@
|
|||
package io.metersphere.service;
|
||||
|
||||
import io.metersphere.commons.utils.BeanUtils;
|
||||
import io.metersphere.track.dto.TestCaseNodeDTO;
|
||||
import io.metersphere.track.dto.TreeNodeDTO;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class NodeTreeService<T extends TreeNodeDTO> {
|
||||
|
||||
protected static final double LIMIT_POS = 64;
|
||||
protected static final double DEFAULT_POS = 65536;
|
||||
|
||||
public List<T> getNodeTrees(List<T> nodes) {
|
||||
List<T> nodeTreeList = new ArrayList<>();
|
||||
Map<Integer, List<T>> nodeLevelMap = new HashMap<>();
|
||||
nodes.forEach(node -> {
|
||||
Integer level = node.getLevel();
|
||||
if (nodeLevelMap.containsKey(level)) {
|
||||
nodeLevelMap.get(level).add(node);
|
||||
} else {
|
||||
List<T> testCaseNodes = new ArrayList<>();
|
||||
testCaseNodes.add(node);
|
||||
nodeLevelMap.put(node.getLevel(), testCaseNodes);
|
||||
}
|
||||
});
|
||||
List<T> rootNodes = Optional.ofNullable(nodeLevelMap.get(1)).orElse(new ArrayList<>());
|
||||
rootNodes.forEach(rootNode -> nodeTreeList.add(buildNodeTree(nodeLevelMap, rootNode)));
|
||||
return nodeTreeList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归构建节点树
|
||||
*
|
||||
* @param nodeLevelMap
|
||||
* @param rootNode
|
||||
* @return
|
||||
*/
|
||||
public T buildNodeTree(Map<Integer, List<T>> nodeLevelMap, T rootNode) {
|
||||
|
||||
T nodeTree = (T) new TreeNodeDTO();
|
||||
BeanUtils.copyBean(nodeTree, rootNode);
|
||||
nodeTree.setLabel(rootNode.getName());
|
||||
|
||||
List<T> lowerNodes = nodeLevelMap.get(rootNode.getLevel() + 1);
|
||||
if (lowerNodes == null) {
|
||||
return nodeTree;
|
||||
}
|
||||
|
||||
List<T> children = Optional.ofNullable(nodeTree.getChildren()).orElse(new ArrayList<>());
|
||||
|
||||
lowerNodes.forEach(node -> {
|
||||
if (node.getParentId() != null && node.getParentId().equals(rootNode.getId())) {
|
||||
children.add(buildNodeTree(nodeLevelMap, node));
|
||||
nodeTree.setChildren(children);
|
||||
}
|
||||
});
|
||||
return nodeTree;
|
||||
}
|
||||
|
||||
/**
|
||||
* 去除没有数据的节点
|
||||
*
|
||||
* @param rootNode
|
||||
* @param nodeIds
|
||||
* @return 是否剪枝
|
||||
*/
|
||||
public boolean pruningTree(T rootNode, List<String> nodeIds) {
|
||||
|
||||
List<T> children = rootNode.getChildren();
|
||||
|
||||
if (children == null || children.isEmpty()) {
|
||||
//叶子节点,并且该节点无数据
|
||||
if (!nodeIds.contains(rootNode.getId())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (children != null) {
|
||||
Iterator<T> iterator = children.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
T subNode = iterator.next();
|
||||
if (pruningTree(subNode, nodeIds)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
if (children.isEmpty() && !nodeIds.contains(rootNode.getId())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据目标节点路径,创建相关节点
|
||||
*
|
||||
* @param pathIterator 遍历子路径
|
||||
* @param path 当前路径
|
||||
* @param treeNode 当前节点
|
||||
* @param pathMap 记录节点路径对应的nodeId
|
||||
*/
|
||||
protected void createNodeByPathIterator(Iterator<String> pathIterator, String path, TestCaseNodeDTO treeNode,
|
||||
Map<String, String> pathMap, String projectId, Integer level) {
|
||||
|
||||
List<TestCaseNodeDTO> children = treeNode.getChildren();
|
||||
|
||||
if (children == null || children.isEmpty() || !pathIterator.hasNext()) {
|
||||
pathMap.put(path, treeNode.getId());
|
||||
if (pathIterator.hasNext()) {
|
||||
createNodeByPath(pathIterator, pathIterator.next().trim(), treeNode, projectId, level, path, pathMap);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
String nodeName = pathIterator.next().trim();
|
||||
|
||||
Boolean hasNode = false;
|
||||
|
||||
for (TestCaseNodeDTO child : children) {
|
||||
if (StringUtils.equals(nodeName, child.getName())) {
|
||||
hasNode = true;
|
||||
createNodeByPathIterator(pathIterator, path + "/" + child.getName(),
|
||||
child, pathMap, projectId, level + 1);
|
||||
}
|
||||
;
|
||||
}
|
||||
|
||||
//若子节点中不包含该目标节点,则在该节点下创建
|
||||
if (!hasNode) {
|
||||
createNodeByPath(pathIterator, nodeName, treeNode, projectId, level, path, pathMap);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pathIterator 迭代器,遍历子节点
|
||||
* @param nodeName 当前节点
|
||||
* @param pNode 父节点
|
||||
*/
|
||||
protected void createNodeByPath(Iterator<String> pathIterator, String nodeName,
|
||||
TestCaseNodeDTO pNode, String projectId, Integer level,
|
||||
String rootPath, Map<String, String> pathMap) {
|
||||
|
||||
StringBuilder path = new StringBuilder(rootPath);
|
||||
|
||||
path.append("/" + nodeName);
|
||||
|
||||
String pid = null;
|
||||
//创建过不创建
|
||||
if (pathMap.get(path.toString()) != null) {
|
||||
pid = pathMap.get(path.toString());
|
||||
level++;
|
||||
} else {
|
||||
pid = insertNode(nodeName, pNode == null ? null : pNode.getId(), projectId, level);
|
||||
pathMap.put(path.toString(), pid);
|
||||
level++;
|
||||
}
|
||||
|
||||
while (pathIterator.hasNext()) {
|
||||
String nextNodeName = pathIterator.next();
|
||||
path.append("/" + nextNodeName);
|
||||
if (pathMap.get(path.toString()) != null) {
|
||||
pid = pathMap.get(path.toString());
|
||||
level++;
|
||||
} else {
|
||||
pid = insertNode(nextNodeName, pid, projectId, level);
|
||||
pathMap.put(path.toString(), pid);
|
||||
level++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 测试用例同级模块排序
|
||||
*
|
||||
* @param ids 被拖拽模块相邻的前一个模块 id,
|
||||
* 被拖拽的模块 id,
|
||||
* 被拖拽模块相邻的后一个模块 id
|
||||
*/
|
||||
public void sort(List<String> ids) {
|
||||
// 获取相邻节点 id
|
||||
String before = ids.get(0);
|
||||
String id = ids.get(1);
|
||||
String after = ids.get(2);
|
||||
|
||||
T beforeNode = null;
|
||||
T afterNode = null;
|
||||
|
||||
T node = getNode(id);
|
||||
|
||||
// 获取相邻节点
|
||||
if (StringUtils.isNotBlank(before)) {
|
||||
beforeNode = getNode(before);
|
||||
beforeNode = beforeNode.getLevel().equals(node.getLevel()) ? beforeNode : null;
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(after)) {
|
||||
afterNode = getNode(after);
|
||||
afterNode = afterNode.getLevel().equals(node.getLevel()) ? afterNode : null;
|
||||
}
|
||||
|
||||
double pos;
|
||||
|
||||
if (beforeNode == null) {
|
||||
pos = afterNode != null ? afterNode.getPos() / 2.0 : DEFAULT_POS;
|
||||
} else {
|
||||
pos = afterNode != null ? (beforeNode.getPos() + afterNode.getPos()) / 2.0 : beforeNode.getPos() + DEFAULT_POS;
|
||||
}
|
||||
|
||||
node.setPos(pos);
|
||||
updatePos(node.getId(), node.getPos());
|
||||
|
||||
// pos 低于阈值时,触发更新方法,重新计算此目录的所有同级目录的 pos 值
|
||||
if (pos < LIMIT_POS) {
|
||||
refreshPos(node.getProjectId(), node.getLevel(), node.getParentId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String insertNode(String nodeName, String pId, String projectId, Integer level) {
|
||||
return "";
|
||||
}
|
||||
|
||||
public void updatePos(String id, Double pos) {
|
||||
}
|
||||
|
||||
protected void refreshPos(String projectId, int level, String parentId) {
|
||||
}
|
||||
|
||||
public T getNode(String id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -4,6 +4,7 @@ import io.metersphere.base.domain.Project;
|
|||
import io.metersphere.base.domain.TestCaseNode;
|
||||
import io.metersphere.base.domain.TestCaseNodeExample;
|
||||
import io.metersphere.base.mapper.TestCaseNodeMapper;
|
||||
import io.metersphere.base.mapper.ext.ExtTestCaseNodeMapper;
|
||||
import io.metersphere.commons.constants.TestPlanTestCaseStatus;
|
||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||
import io.metersphere.commons.utils.MathUtils;
|
||||
|
@ -29,11 +30,9 @@ public class ReportResultComponent extends ReportComponent {
|
|||
|
||||
public void init() {
|
||||
TestCaseNodeService testCaseNodeService = (TestCaseNodeService) CommonBeanFactory.getBean("testCaseNodeService");
|
||||
TestCaseNodeMapper testCaseNodeMapper = (TestCaseNodeMapper) CommonBeanFactory.getBean("testCaseNodeMapper");
|
||||
ExtTestCaseNodeMapper extTestCaseNodeMapper = (ExtTestCaseNodeMapper) CommonBeanFactory.getBean("extTestCaseNodeMapper");
|
||||
TestPlanProjectService testPlanProjectService = (TestPlanProjectService) CommonBeanFactory.getBean("testPlanProjectService");
|
||||
TestCaseNodeExample testCaseNodeExample = new TestCaseNodeExample();
|
||||
testCaseNodeExample.createCriteria().andProjectIdIn(testPlanProjectService.getProjectIdsByPlanId(testPlan.getId()));
|
||||
List<TestCaseNode> nodes = testCaseNodeMapper.selectByExample(testCaseNodeExample);
|
||||
List<TestCaseNodeDTO> nodes = extTestCaseNodeMapper.getNodeTreeByProjectIds(testPlanProjectService.getProjectIdsByPlanId(testPlan.getId()));
|
||||
nodeTrees = testCaseNodeService.getNodeTrees(nodes);
|
||||
nodeTrees.forEach(item -> {
|
||||
Set<String> childIds = new HashSet<>();
|
||||
|
|
|
@ -1,16 +1,9 @@
|
|||
package io.metersphere.track.dto;
|
||||
|
||||
import io.metersphere.base.domain.TestCaseNode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class TestCaseNodeDTO extends TestCaseNode {
|
||||
|
||||
private String label;
|
||||
private List<TestCaseNodeDTO> children;
|
||||
|
||||
public class TestCaseNodeDTO extends TreeNodeDTO<TestCaseNodeDTO> {
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
package io.metersphere.track.dto;
|
||||
|
||||
import io.metersphere.api.dto.definition.ApiModuleDTO;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class TreeNodeDTO<T> {
|
||||
private String id;
|
||||
|
||||
private String projectId;
|
||||
|
||||
private String name;
|
||||
|
||||
private String parentId;
|
||||
|
||||
private Integer level;
|
||||
|
||||
private Long createTime;
|
||||
|
||||
private Long updateTime;
|
||||
|
||||
private Double pos;
|
||||
|
||||
private String label;
|
||||
|
||||
private List<T> children;
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
|
@ -5,11 +5,12 @@ import com.google.common.util.concurrent.AtomicDouble;
|
|||
import io.metersphere.base.domain.*;
|
||||
import io.metersphere.base.mapper.*;
|
||||
import io.metersphere.base.mapper.ext.ExtTestCaseMapper;
|
||||
import io.metersphere.base.mapper.ext.ExtTestCaseNodeMapper;
|
||||
import io.metersphere.commons.constants.TestCaseConstants;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.BeanUtils;
|
||||
import io.metersphere.exception.ExcelException;
|
||||
import io.metersphere.i18n.Translator;
|
||||
import io.metersphere.service.NodeTreeService;
|
||||
import io.metersphere.track.dto.TestCaseDTO;
|
||||
import io.metersphere.track.dto.TestCaseNodeDTO;
|
||||
import io.metersphere.track.request.testcase.DragNodeRequest;
|
||||
|
@ -29,11 +30,13 @@ import java.util.stream.Collectors;
|
|||
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class TestCaseNodeService {
|
||||
public class TestCaseNodeService extends NodeTreeService<TestCaseNodeDTO> {
|
||||
|
||||
@Resource
|
||||
TestCaseNodeMapper testCaseNodeMapper;
|
||||
@Resource
|
||||
ExtTestCaseNodeMapper extTestCaseNodeMapper;
|
||||
@Resource
|
||||
TestCaseMapper testCaseMapper;
|
||||
@Resource
|
||||
TestPlanMapper testPlanMapper;
|
||||
|
@ -54,8 +57,6 @@ public class TestCaseNodeService {
|
|||
@Resource
|
||||
TestCaseReviewMapper testCaseReviewMapper;
|
||||
|
||||
private static final double LIMIT_POS = 64;
|
||||
|
||||
public String addNode(TestCaseNode node) {
|
||||
validateNode(node);
|
||||
node.setCreateTime(System.currentTimeMillis());
|
||||
|
@ -96,64 +97,8 @@ public class TestCaseNodeService {
|
|||
}
|
||||
|
||||
public List<TestCaseNodeDTO> getNodeTreeByProjectId(String projectId) {
|
||||
TestCaseNodeExample testCaseNodeExample = new TestCaseNodeExample();
|
||||
testCaseNodeExample.createCriteria().andProjectIdEqualTo(projectId);
|
||||
testCaseNodeExample.setOrderByClause("pos asc");
|
||||
List<TestCaseNode> nodes = testCaseNodeMapper.selectByExample(testCaseNodeExample);
|
||||
return getNodeTrees(nodes);
|
||||
}
|
||||
|
||||
public List<TestCaseNodeDTO> getNodeTrees(List<TestCaseNode> nodes) {
|
||||
|
||||
List<TestCaseNodeDTO> nodeTreeList = new ArrayList<>();
|
||||
|
||||
Map<Integer, List<TestCaseNode>> nodeLevelMap = new HashMap<>();
|
||||
|
||||
nodes.forEach(node -> {
|
||||
Integer level = node.getLevel();
|
||||
if (nodeLevelMap.containsKey(level)) {
|
||||
nodeLevelMap.get(level).add(node);
|
||||
} else {
|
||||
List<TestCaseNode> testCaseNodes = new ArrayList<>();
|
||||
testCaseNodes.add(node);
|
||||
nodeLevelMap.put(node.getLevel(), testCaseNodes);
|
||||
}
|
||||
});
|
||||
|
||||
List<TestCaseNode> rootNodes = Optional.ofNullable(nodeLevelMap.get(1)).orElse(new ArrayList<>());
|
||||
rootNodes.forEach(rootNode -> nodeTreeList.add(buildNodeTree(nodeLevelMap, rootNode)));
|
||||
|
||||
return nodeTreeList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归构建节点树
|
||||
*
|
||||
* @param nodeLevelMap
|
||||
* @param rootNode
|
||||
* @return
|
||||
*/
|
||||
private TestCaseNodeDTO buildNodeTree(Map<Integer, List<TestCaseNode>> nodeLevelMap, TestCaseNode rootNode) {
|
||||
|
||||
TestCaseNodeDTO nodeTree = new TestCaseNodeDTO();
|
||||
BeanUtils.copyBean(nodeTree, rootNode);
|
||||
nodeTree.setLabel(rootNode.getName());
|
||||
|
||||
List<TestCaseNode> lowerNodes = nodeLevelMap.get(rootNode.getLevel() + 1);
|
||||
if (lowerNodes == null) {
|
||||
return nodeTree;
|
||||
}
|
||||
|
||||
List<TestCaseNodeDTO> children = Optional.ofNullable(nodeTree.getChildren()).orElse(new ArrayList<>());
|
||||
|
||||
lowerNodes.forEach(node -> {
|
||||
if (node.getParentId() != null && node.getParentId().equals(rootNode.getId())) {
|
||||
children.add(buildNodeTree(nodeLevelMap, node));
|
||||
nodeTree.setChildren(children);
|
||||
}
|
||||
});
|
||||
|
||||
return nodeTree;
|
||||
List<TestCaseNodeDTO> testCaseNodes = extTestCaseNodeMapper.getNodeTreeByProjectId(projectId);
|
||||
return getNodeTrees(testCaseNodes);
|
||||
}
|
||||
|
||||
public int editNode(DragNodeRequest request) {
|
||||
|
@ -247,9 +192,7 @@ public class TestCaseNodeService {
|
|||
return null;
|
||||
}
|
||||
|
||||
TestCaseNodeExample testCaseNodeExample = new TestCaseNodeExample();
|
||||
testCaseNodeExample.createCriteria().andProjectIdEqualTo(projectId);
|
||||
List<TestCaseNode> nodes = testCaseNodeMapper.selectByExample(testCaseNodeExample);
|
||||
List<TestCaseNodeDTO> testCaseNodes = extTestCaseNodeMapper.getNodeTreeByProjectId(projectId);
|
||||
|
||||
List<String> caseIds = testPlanTestCases.stream()
|
||||
.map(TestPlanTestCase::getCaseId)
|
||||
|
@ -261,7 +204,7 @@ public class TestCaseNodeService {
|
|||
.map(TestCase::getNodeId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<TestCaseNodeDTO> nodeTrees = getNodeTrees(nodes);
|
||||
List<TestCaseNodeDTO> nodeTrees = getNodeTrees(testCaseNodes);
|
||||
|
||||
Iterator<TestCaseNodeDTO> iterator = nodeTrees.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
|
@ -280,9 +223,7 @@ public class TestCaseNodeService {
|
|||
return null;
|
||||
}
|
||||
|
||||
TestCaseNodeExample testCaseNodeExample = new TestCaseNodeExample();
|
||||
testCaseNodeExample.createCriteria().andProjectIdEqualTo(projectId);
|
||||
List<TestCaseNode> nodes = testCaseNodeMapper.selectByExample(testCaseNodeExample);
|
||||
List<TestCaseNodeDTO> testCaseNodes = extTestCaseNodeMapper.getNodeTreeByProjectId(projectId);
|
||||
|
||||
|
||||
TestCaseExample testCaseExample = new TestCaseExample();
|
||||
|
@ -291,7 +232,7 @@ public class TestCaseNodeService {
|
|||
.map(TestCase::getNodeId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<TestCaseNodeDTO> nodeTrees = getNodeTrees(nodes);
|
||||
List<TestCaseNodeDTO> nodeTrees = getNodeTrees(testCaseNodes);
|
||||
|
||||
Iterator<TestCaseNodeDTO> iterator = nodeTrees.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
|
@ -304,41 +245,6 @@ public class TestCaseNodeService {
|
|||
return nodeTrees;
|
||||
}
|
||||
|
||||
/**
|
||||
* 去除没有数据的节点
|
||||
*
|
||||
* @param rootNode
|
||||
* @param nodeIds
|
||||
* @return 是否剪枝
|
||||
*/
|
||||
public boolean pruningTree(TestCaseNodeDTO rootNode, List<String> nodeIds) {
|
||||
|
||||
List<TestCaseNodeDTO> children = rootNode.getChildren();
|
||||
|
||||
if (children == null || children.isEmpty()) {
|
||||
//叶子节点,并且该节点无数据
|
||||
if (!nodeIds.contains(rootNode.getId())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (children != null) {
|
||||
Iterator<TestCaseNodeDTO> iterator = children.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
TestCaseNodeDTO subNode = iterator.next();
|
||||
if (pruningTree(subNode, nodeIds)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
if (children.isEmpty() && !nodeIds.contains(rootNode.getId())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<TestCaseNodeDTO> getAllNodeByPlanId(QueryNodeRequest request) {
|
||||
String planId = request.getTestPlanId();
|
||||
String projectId = request.getProjectId();
|
||||
|
@ -405,86 +311,8 @@ public class TestCaseNodeService {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据目标节点路径,创建相关节点
|
||||
*
|
||||
* @param pathIterator 遍历子路径
|
||||
* @param path 当前路径
|
||||
* @param treeNode 当前节点
|
||||
* @param pathMap 记录节点路径对应的nodeId
|
||||
*/
|
||||
private void createNodeByPathIterator(Iterator<String> pathIterator, String path, TestCaseNodeDTO treeNode,
|
||||
Map<String, String> pathMap, String projectId, Integer level) {
|
||||
|
||||
List<TestCaseNodeDTO> children = treeNode.getChildren();
|
||||
|
||||
if (children == null || children.isEmpty() || !pathIterator.hasNext()) {
|
||||
pathMap.put(path, treeNode.getId());
|
||||
if (pathIterator.hasNext()) {
|
||||
createNodeByPath(pathIterator, pathIterator.next().trim(), treeNode, projectId, level, path, pathMap);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
String nodeName = pathIterator.next().trim();
|
||||
|
||||
Boolean hasNode = false;
|
||||
|
||||
for (TestCaseNodeDTO child : children) {
|
||||
if (StringUtils.equals(nodeName, child.getName())) {
|
||||
hasNode = true;
|
||||
createNodeByPathIterator(pathIterator, path + "/" + child.getName(),
|
||||
child, pathMap, projectId, level + 1);
|
||||
}
|
||||
;
|
||||
}
|
||||
|
||||
//若子节点中不包含该目标节点,则在该节点下创建
|
||||
if (!hasNode) {
|
||||
createNodeByPath(pathIterator, nodeName, treeNode, projectId, level, path, pathMap);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pathIterator 迭代器,遍历子节点
|
||||
* @param nodeName 当前节点
|
||||
* @param pNode 父节点
|
||||
*/
|
||||
private void createNodeByPath(Iterator<String> pathIterator, String nodeName,
|
||||
TestCaseNodeDTO pNode, String projectId, Integer level,
|
||||
String rootPath, Map<String, String> pathMap) {
|
||||
|
||||
StringBuilder path = new StringBuilder(rootPath);
|
||||
|
||||
path.append("/" + nodeName);
|
||||
|
||||
String pid = null;
|
||||
//创建过不创建
|
||||
if (pathMap.get(path.toString()) != null) {
|
||||
pid = pathMap.get(path.toString());
|
||||
level++;
|
||||
} else {
|
||||
pid = insertTestCaseNode(nodeName, pNode == null ? null : pNode.getId(), projectId, level);
|
||||
pathMap.put(path.toString(), pid);
|
||||
level++;
|
||||
}
|
||||
|
||||
while (pathIterator.hasNext()) {
|
||||
String nextNodeName = pathIterator.next();
|
||||
path.append("/" + nextNodeName);
|
||||
if (pathMap.get(path.toString()) != null) {
|
||||
pid = pathMap.get(path.toString());
|
||||
level++;
|
||||
} else {
|
||||
pid = insertTestCaseNode(nextNodeName, pid, projectId, level);
|
||||
pathMap.put(path.toString(), pid);
|
||||
level++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String insertTestCaseNode(String nodeName, String pId, String projectId, Integer level) {
|
||||
@Override
|
||||
public String insertNode(String nodeName, String pId, String projectId, Integer level) {
|
||||
TestCaseNode testCaseNode = new TestCaseNode();
|
||||
testCaseNode.setName(nodeName.trim());
|
||||
testCaseNode.setParentId(pId);
|
||||
|
@ -587,51 +415,14 @@ public class TestCaseNodeService {
|
|||
return testCaseNodeMapper.selectByPrimaryKey(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestCaseNodeDTO getNode(String id) {
|
||||
return extTestCaseNodeMapper.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试用例同级模块排序
|
||||
*
|
||||
* @param ids 被拖拽模块相邻的前一个模块 id,
|
||||
* 被拖拽的模块 id,
|
||||
* 被拖拽模块相邻的后一个模块 id
|
||||
*/
|
||||
public void sort(List<String> ids) {
|
||||
// 获取相邻节点 id
|
||||
String before = ids.get(0);
|
||||
String id = ids.get(1);
|
||||
String after = ids.get(2);
|
||||
|
||||
TestCaseNode beforeCase = null;
|
||||
TestCaseNode afterCase = null;
|
||||
|
||||
TestCaseNode caseNode = getCaseNode(id);
|
||||
|
||||
// 获取相邻节点
|
||||
if (StringUtils.isNotBlank(before)) {
|
||||
beforeCase = getCaseNode(before);
|
||||
beforeCase = beforeCase.getLevel().equals(caseNode.getLevel()) ? beforeCase : null;
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(after)) {
|
||||
afterCase = getCaseNode(after);
|
||||
afterCase = afterCase.getLevel().equals(caseNode.getLevel()) ? afterCase : null;
|
||||
}
|
||||
|
||||
double pos;
|
||||
|
||||
if (beforeCase == null) {
|
||||
pos = afterCase != null ? afterCase.getPos() / 2.0 : 65536;
|
||||
} else {
|
||||
pos = afterCase != null ? (beforeCase.getPos() + afterCase.getPos()) / 2.0 : beforeCase.getPos() + 65536;
|
||||
}
|
||||
|
||||
caseNode.setPos(pos);
|
||||
testCaseNodeMapper.updateByPrimaryKeySelective(caseNode);
|
||||
|
||||
// pos 低于阈值时,触发更新方法,重新计算此目录的所有同级目录的 pos 值
|
||||
if (pos < LIMIT_POS) {
|
||||
refreshPos(caseNode.getProjectId(), caseNode.getLevel(), caseNode.getParentId());
|
||||
}
|
||||
@Override
|
||||
public void updatePos(String id, Double pos) {
|
||||
extTestCaseNodeMapper.updatePos(id, pos);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -661,14 +452,15 @@ public class TestCaseNodeService {
|
|||
* @param level node level
|
||||
* @param parentId node parent id
|
||||
*/
|
||||
private void refreshPos(String projectId, int level, String parentId) {
|
||||
@Override
|
||||
protected void refreshPos(String projectId, int level, String parentId) {
|
||||
List<TestCaseNode> nodes = getPos(projectId, level, parentId, "pos asc");
|
||||
if (!CollectionUtils.isEmpty(nodes)) {
|
||||
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
||||
TestCaseNodeMapper testCaseNodeMapper = sqlSession.getMapper(TestCaseNodeMapper.class);
|
||||
AtomicDouble pos = new AtomicDouble(65536);
|
||||
AtomicDouble pos = new AtomicDouble(DEFAULT_POS);
|
||||
nodes.forEach((node) -> {
|
||||
node.setPos(pos.getAndAdd(65536));
|
||||
node.setPos(pos.getAndAdd(DEFAULT_POS));
|
||||
testCaseNodeMapper.updateByPrimaryKey(node);
|
||||
});
|
||||
sqlSession.flushStatements();
|
||||
|
@ -687,9 +479,9 @@ public class TestCaseNodeService {
|
|||
private double getNextLevelPos(String projectId, int level, String parentId) {
|
||||
List<TestCaseNode> list = getPos(projectId, level, parentId, "pos desc");
|
||||
if (!CollectionUtils.isEmpty(list) && list.get(0) != null && list.get(0).getPos() != null) {
|
||||
return list.get(0).getPos() + 65536;
|
||||
return list.get(0).getPos() + DEFAULT_POS;
|
||||
} else {
|
||||
return 65536;
|
||||
return DEFAULT_POS;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 1fe20ba15a7ca3fe9f77ddf866021e7c7dfe5969
|
||||
Subproject commit 61397c16728a63493507679f7e0940d9099f337f
|
|
@ -5,6 +5,7 @@ CREATE TABLE IF NOT EXISTS `api_module` (
|
|||
`protocol` varchar(64) NOT NULL COMMENT 'Node protocol',
|
||||
`parent_id` varchar(50) DEFAULT NULL COMMENT 'Parent node ID',
|
||||
`level` int(10) DEFAULT 1 COMMENT 'Node level',
|
||||
`pos` double DEFAULT NULL COMMENT 'Node order',
|
||||
`create_time` bigint(13) NOT NULL COMMENT 'Create timestamp',
|
||||
`update_time` bigint(13) NOT NULL COMMENT 'Update timestamp',
|
||||
PRIMARY KEY (`id`)
|
||||
|
|
|
@ -64,8 +64,8 @@
|
|||
|
||||
<!--要生成的数据库表 -->
|
||||
|
||||
<table tableName="api_scenario"/>
|
||||
<table tableName="api_scenario_report"/>
|
||||
<table tableName="api_module"/>
|
||||
<!--<table tableName="api_scenario_report"/>-->
|
||||
|
||||
</context>
|
||||
</generatorConfiguration>
|
|
@ -24,8 +24,10 @@
|
|||
<el-tag size="mini" style="margin-left: 20px" v-if="request.referenced ==='REF'">{{ $t('api_test.scenario.reference') }}</el-tag>
|
||||
<div style="margin-right: 20px; float: right">
|
||||
<i class="icon el-icon-arrow-right" :class="{'is-active': request.active}"
|
||||
@click="active(request)" v-if="request.referenced!=undefined && request.referenced!='Deleted' && request.referenced!='REF'"/>
|
||||
@click="active(request)"/>
|
||||
<el-switch v-model="request.enable" style="margin-left: 10px"/>
|
||||
<el-button @click="run" :tip="$t('api_test.run')" icon="el-icon-video-play"
|
||||
style="background-color: #409EFF;color: white;margin-left: 10px" size="mini" circle/>
|
||||
<el-button size="mini" icon="el-icon-copy-document" circle @click="copyRow" style="margin-left: 10px"/>
|
||||
<el-button size="mini" icon="el-icon-delete" type="danger" circle @click="remove" style="margin-left: 10px"/>
|
||||
</div>
|
||||
|
@ -45,6 +47,10 @@
|
|||
<ms-tcp-basis-parameters :request="request" v-if="request.protocol==='TCP'"/>
|
||||
<ms-sql-basis-parameters :request="request" v-if="request.protocol==='SQL'"/>
|
||||
<ms-dubbo-basis-parameters :request="request" v-if="request.protocol==='DUBBO' || request.protocol==='dubbo://'"/>
|
||||
|
||||
<p class="tip">{{$t('api_test.definition.request.res_param')}} </p>
|
||||
<ms-request-result-tail :response="request.requestResult" ref="runResult"/>
|
||||
|
||||
<!-- 保存操作 -->
|
||||
<el-button type="primary" size="small" style="margin: 20px; float: right" @click="saveTestCase(item)" v-if="!request.referenced">
|
||||
{{$t('commons.save')}}
|
||||
|
@ -52,6 +58,9 @@
|
|||
</div>
|
||||
</el-collapse-transition>
|
||||
</el-card>
|
||||
<!-- 执行组件 -->
|
||||
<ms-run :debug="false" :reportId="reportId" :run-data="runData"
|
||||
@runRefresh="runRefresh" ref="runTest"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -61,29 +70,27 @@
|
|||
import MsDubboBasisParameters from "../../definition/components/request/dubbo/BasisParameters";
|
||||
import MsApiRequestForm from "../../definition/components/request/http/ApiRequestForm";
|
||||
import {REQ_METHOD} from "../../definition/model/JsonData";
|
||||
import MsRequestResultTail from "../../definition/components/response/RequestResultTail";
|
||||
import MsRun from "../../definition/components/Run";
|
||||
import {getUUID} from "@/common/js/utils";
|
||||
|
||||
export default {
|
||||
name: "MsApiComponent",
|
||||
props: {
|
||||
request: {},
|
||||
node: {},
|
||||
currentEnvironmentId: String,
|
||||
},
|
||||
components: {MsSqlBasisParameters, MsTcpBasisParameters, MsDubboBasisParameters, MsApiRequestForm},
|
||||
components: {MsSqlBasisParameters, MsTcpBasisParameters, MsDubboBasisParameters, MsApiRequestForm, MsRequestResultTail, MsRun},
|
||||
data() {
|
||||
return {loading: false, reqOptions: REQ_METHOD,}
|
||||
return {loading: false, reqOptions: REQ_METHOD, reportId: "", runData: []}
|
||||
},
|
||||
created() {
|
||||
if (this.request.id && this.request.referenced === 'REF') {
|
||||
this.$get("/api/definition/get/" + this.request.id, response => {
|
||||
if (response.data) {
|
||||
this.request.name = response.data.name;
|
||||
this.reload();
|
||||
} else {
|
||||
this.request.referenced = "Deleted";
|
||||
}
|
||||
})
|
||||
if (!this.request.requestResult) {
|
||||
this.request.requestResult = {responseResult: {}};
|
||||
}
|
||||
|
||||
// 加载引用对象数据
|
||||
this.getApiInfo();
|
||||
if (this.request.protocol === 'HTTP') {
|
||||
try {
|
||||
let urlObject = new URL(this.request.url);
|
||||
|
@ -105,10 +112,45 @@
|
|||
copyRow() {
|
||||
this.$emit('copyRow', this.request, this.node);
|
||||
},
|
||||
getApiInfo() {
|
||||
if (this.request.id && this.request.referenced === 'REF') {
|
||||
let requestResult = this.request.requestResult;
|
||||
this.$get("/api/definition/get/" + this.request.id, response => {
|
||||
if (response.data) {
|
||||
Object.assign(this.request, JSON.parse(response.data.request));
|
||||
this.request.name = response.data.name;
|
||||
this.request.path = response.data.path;
|
||||
this.request.method = response.data.method;
|
||||
this.request.url = response.data.path;
|
||||
this.request.requestResult = requestResult;
|
||||
this.reload();
|
||||
} else {
|
||||
this.request.referenced = "Deleted";
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
active(item) {
|
||||
item.active = !item.active;
|
||||
this.reload();
|
||||
},
|
||||
run() {
|
||||
if (!this.currentEnvironmentId) {
|
||||
this.$error(this.$t('api_test.environment.select_environment'));
|
||||
return;
|
||||
}
|
||||
this.loading = true;
|
||||
this.runData = [];
|
||||
this.request.useEnvironment = this.currentEnvironmentId;
|
||||
this.runData.push(this.request);
|
||||
/*触发执行操作*/
|
||||
this.reportId = getUUID().substring(0, 8);
|
||||
|
||||
},
|
||||
runRefresh(data) {
|
||||
this.request.requestResult = data;
|
||||
this.loading = false;
|
||||
},
|
||||
reload() {
|
||||
this.loading = true
|
||||
this.$nextTick(() => {
|
||||
|
|
|
@ -186,7 +186,7 @@
|
|||
<!--提取规则-->
|
||||
<ms-api-extract @remove="remove" @copyRow="copyRow" v-if="data.type==='Extract'" customizeStyle="margin-top: 0px" :extract="data" :node="node"/>
|
||||
<!--API 导入 -->
|
||||
<ms-api-component :request="data" @remove="remove" @copyRow="copyRow" v-if="data.type==='HTTPSamplerProxy'||data.type==='DubboSampler'||data.type==='JDBCSampler'||data.type==='TCPSampler'" :node="node"/>
|
||||
<ms-api-component :request="data" :currentEnvironmentId="currentEnvironmentId" @remove="remove" @copyRow="copyRow" v-if="data.type==='HTTPSamplerProxy'||data.type==='DubboSampler'||data.type==='JDBCSampler'||data.type==='TCPSampler'" :node="node"/>
|
||||
</template>
|
||||
</span>
|
||||
</el-tree>
|
||||
|
|
|
@ -186,7 +186,7 @@
|
|||
copyRow(row) {
|
||||
let obj = {};
|
||||
Object.assign(obj, row);
|
||||
row.id = getUUID();
|
||||
obj.id = getUUID();
|
||||
this.request.hashTree.push(obj);
|
||||
this.reload();
|
||||
},
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 5835db186d17a3d305073e58affb4e88a71b32f0
|
||||
Subproject commit 29a8fc09602fde5708af06582ac972d98eb69836
|
Loading…
Reference in New Issue