feat(测试计划): 测试计划组后台相关功能开发
This commit is contained in:
parent
d30cf886f2
commit
0e57b01a8b
|
@ -4,13 +4,13 @@ import io.metersphere.validation.groups.Created;
|
||||||
import io.metersphere.validation.groups.Updated;
|
import io.metersphere.validation.groups.Updated;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
import jakarta.validation.constraints.Size;
|
import jakarta.validation.constraints.Size;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class TestPlan implements Serializable {
|
public class TestPlan implements Serializable {
|
||||||
|
@ -53,7 +53,7 @@ public class TestPlan implements Serializable {
|
||||||
private String type;
|
private String type;
|
||||||
|
|
||||||
@Schema(description = "标签")
|
@Schema(description = "标签")
|
||||||
private List<String> tags;
|
private java.util.List<String> tags;
|
||||||
|
|
||||||
@Schema(description = "创建时间")
|
@Schema(description = "创建时间")
|
||||||
private Long createTime;
|
private Long createTime;
|
||||||
|
@ -79,9 +79,13 @@ public class TestPlan implements Serializable {
|
||||||
@Schema(description = "实际结束时间")
|
@Schema(description = "实际结束时间")
|
||||||
private Long actualEndTime;
|
private Long actualEndTime;
|
||||||
|
|
||||||
@Schema(description = "描述;描述")
|
@Schema(description = "描述")
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
|
@Schema(description = "自定义排序", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@NotNull(message = "{test_plan.pos.not_blank}", groups = {Created.class})
|
||||||
|
private Long pos;
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
public enum Column {
|
public enum Column {
|
||||||
|
@ -102,7 +106,8 @@ public class TestPlan implements Serializable {
|
||||||
plannedEndTime("planned_end_time", "plannedEndTime", "BIGINT", false),
|
plannedEndTime("planned_end_time", "plannedEndTime", "BIGINT", false),
|
||||||
actualStartTime("actual_start_time", "actualStartTime", "BIGINT", false),
|
actualStartTime("actual_start_time", "actualStartTime", "BIGINT", false),
|
||||||
actualEndTime("actual_end_time", "actualEndTime", "BIGINT", false),
|
actualEndTime("actual_end_time", "actualEndTime", "BIGINT", false),
|
||||||
description("description", "description", "VARCHAR", false);
|
description("description", "description", "VARCHAR", false),
|
||||||
|
pos("pos", "pos", "BIGINT", false);
|
||||||
|
|
||||||
private static final String BEGINNING_DELIMITER = "`";
|
private static final String BEGINNING_DELIMITER = "`";
|
||||||
|
|
||||||
|
|
|
@ -1327,6 +1327,66 @@ public class TestPlanExample {
|
||||||
addCriterion("description not between", value1, value2, "description");
|
addCriterion("description not between", value1, value2, "description");
|
||||||
return (Criteria) this;
|
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(Long value) {
|
||||||
|
addCriterion("pos =", value, "pos");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andPosNotEqualTo(Long value) {
|
||||||
|
addCriterion("pos <>", value, "pos");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andPosGreaterThan(Long value) {
|
||||||
|
addCriterion("pos >", value, "pos");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andPosGreaterThanOrEqualTo(Long value) {
|
||||||
|
addCriterion("pos >=", value, "pos");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andPosLessThan(Long value) {
|
||||||
|
addCriterion("pos <", value, "pos");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andPosLessThanOrEqualTo(Long value) {
|
||||||
|
addCriterion("pos <=", value, "pos");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andPosIn(List<Long> values) {
|
||||||
|
addCriterion("pos in", values, "pos");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andPosNotIn(List<Long> values) {
|
||||||
|
addCriterion("pos not in", values, "pos");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andPosBetween(Long value1, Long value2) {
|
||||||
|
addCriterion("pos between", value1, value2, "pos");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andPosNotBetween(Long value1, Long value2) {
|
||||||
|
addCriterion("pos not between", value1, value2, "pos");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Criteria extends GeneratedCriteria {
|
public static class Criteria extends GeneratedCriteria {
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
<result column="actual_start_time" jdbcType="BIGINT" property="actualStartTime" />
|
<result column="actual_start_time" jdbcType="BIGINT" property="actualStartTime" />
|
||||||
<result column="actual_end_time" jdbcType="BIGINT" property="actualEndTime" />
|
<result column="actual_end_time" jdbcType="BIGINT" property="actualEndTime" />
|
||||||
<result column="description" jdbcType="VARCHAR" property="description" />
|
<result column="description" jdbcType="VARCHAR" property="description" />
|
||||||
|
<result column="pos" jdbcType="BIGINT" property="pos" />
|
||||||
</resultMap>
|
</resultMap>
|
||||||
<sql id="Example_Where_Clause">
|
<sql id="Example_Where_Clause">
|
||||||
<where>
|
<where>
|
||||||
|
@ -120,7 +121,7 @@
|
||||||
<sql id="Base_Column_List">
|
<sql id="Base_Column_List">
|
||||||
id, num, project_id, group_id, module_id, `name`, `status`, `type`, tags, create_time,
|
id, num, project_id, group_id, module_id, `name`, `status`, `type`, tags, create_time,
|
||||||
create_user, update_time, update_user, planned_start_time, planned_end_time, actual_start_time,
|
create_user, update_time, update_user, planned_start_time, planned_end_time, actual_start_time,
|
||||||
actual_end_time, description
|
actual_end_time, description, pos
|
||||||
</sql>
|
</sql>
|
||||||
<select id="selectByExample" parameterType="io.metersphere.plan.domain.TestPlanExample" resultMap="BaseResultMap">
|
<select id="selectByExample" parameterType="io.metersphere.plan.domain.TestPlanExample" resultMap="BaseResultMap">
|
||||||
select
|
select
|
||||||
|
@ -158,15 +159,15 @@
|
||||||
`status`, `type`, tags,
|
`status`, `type`, tags,
|
||||||
create_time, create_user, update_time,
|
create_time, create_user, update_time,
|
||||||
update_user, planned_start_time, planned_end_time,
|
update_user, planned_start_time, planned_end_time,
|
||||||
actual_start_time, actual_end_time, description
|
actual_start_time, actual_end_time, description,
|
||||||
)
|
pos)
|
||||||
values (#{id,jdbcType=VARCHAR}, #{num,jdbcType=BIGINT}, #{projectId,jdbcType=VARCHAR},
|
values (#{id,jdbcType=VARCHAR}, #{num,jdbcType=BIGINT}, #{projectId,jdbcType=VARCHAR},
|
||||||
#{groupId,jdbcType=VARCHAR}, #{moduleId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
|
#{groupId,jdbcType=VARCHAR}, #{moduleId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
|
||||||
#{status,jdbcType=VARCHAR}, #{type,jdbcType=VARCHAR}, #{tags,jdbcType=VARCHAR,typeHandler=io.metersphere.handler.ListTypeHandler},
|
#{status,jdbcType=VARCHAR}, #{type,jdbcType=VARCHAR}, #{tags,jdbcType=VARCHAR,typeHandler=io.metersphere.handler.ListTypeHandler},
|
||||||
#{createTime,jdbcType=BIGINT}, #{createUser,jdbcType=VARCHAR}, #{updateTime,jdbcType=BIGINT},
|
#{createTime,jdbcType=BIGINT}, #{createUser,jdbcType=VARCHAR}, #{updateTime,jdbcType=BIGINT},
|
||||||
#{updateUser,jdbcType=VARCHAR}, #{plannedStartTime,jdbcType=BIGINT}, #{plannedEndTime,jdbcType=BIGINT},
|
#{updateUser,jdbcType=VARCHAR}, #{plannedStartTime,jdbcType=BIGINT}, #{plannedEndTime,jdbcType=BIGINT},
|
||||||
#{actualStartTime,jdbcType=BIGINT}, #{actualEndTime,jdbcType=BIGINT}, #{description,jdbcType=VARCHAR}
|
#{actualStartTime,jdbcType=BIGINT}, #{actualEndTime,jdbcType=BIGINT}, #{description,jdbcType=VARCHAR},
|
||||||
)
|
#{pos,jdbcType=BIGINT})
|
||||||
</insert>
|
</insert>
|
||||||
<insert id="insertSelective" parameterType="io.metersphere.plan.domain.TestPlan">
|
<insert id="insertSelective" parameterType="io.metersphere.plan.domain.TestPlan">
|
||||||
insert into test_plan
|
insert into test_plan
|
||||||
|
@ -225,6 +226,9 @@
|
||||||
<if test="description != null">
|
<if test="description != null">
|
||||||
description,
|
description,
|
||||||
</if>
|
</if>
|
||||||
|
<if test="pos != null">
|
||||||
|
pos,
|
||||||
|
</if>
|
||||||
</trim>
|
</trim>
|
||||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||||
<if test="id != null">
|
<if test="id != null">
|
||||||
|
@ -281,6 +285,9 @@
|
||||||
<if test="description != null">
|
<if test="description != null">
|
||||||
#{description,jdbcType=VARCHAR},
|
#{description,jdbcType=VARCHAR},
|
||||||
</if>
|
</if>
|
||||||
|
<if test="pos != null">
|
||||||
|
#{pos,jdbcType=BIGINT},
|
||||||
|
</if>
|
||||||
</trim>
|
</trim>
|
||||||
</insert>
|
</insert>
|
||||||
<select id="countByExample" parameterType="io.metersphere.plan.domain.TestPlanExample" resultType="java.lang.Long">
|
<select id="countByExample" parameterType="io.metersphere.plan.domain.TestPlanExample" resultType="java.lang.Long">
|
||||||
|
@ -346,6 +353,9 @@
|
||||||
<if test="record.description != null">
|
<if test="record.description != null">
|
||||||
description = #{record.description,jdbcType=VARCHAR},
|
description = #{record.description,jdbcType=VARCHAR},
|
||||||
</if>
|
</if>
|
||||||
|
<if test="record.pos != null">
|
||||||
|
pos = #{record.pos,jdbcType=BIGINT},
|
||||||
|
</if>
|
||||||
</set>
|
</set>
|
||||||
<if test="_parameter != null">
|
<if test="_parameter != null">
|
||||||
<include refid="Update_By_Example_Where_Clause" />
|
<include refid="Update_By_Example_Where_Clause" />
|
||||||
|
@ -370,7 +380,8 @@
|
||||||
planned_end_time = #{record.plannedEndTime,jdbcType=BIGINT},
|
planned_end_time = #{record.plannedEndTime,jdbcType=BIGINT},
|
||||||
actual_start_time = #{record.actualStartTime,jdbcType=BIGINT},
|
actual_start_time = #{record.actualStartTime,jdbcType=BIGINT},
|
||||||
actual_end_time = #{record.actualEndTime,jdbcType=BIGINT},
|
actual_end_time = #{record.actualEndTime,jdbcType=BIGINT},
|
||||||
description = #{record.description,jdbcType=VARCHAR}
|
description = #{record.description,jdbcType=VARCHAR},
|
||||||
|
pos = #{record.pos,jdbcType=BIGINT}
|
||||||
<if test="_parameter != null">
|
<if test="_parameter != null">
|
||||||
<include refid="Update_By_Example_Where_Clause" />
|
<include refid="Update_By_Example_Where_Clause" />
|
||||||
</if>
|
</if>
|
||||||
|
@ -429,6 +440,9 @@
|
||||||
<if test="description != null">
|
<if test="description != null">
|
||||||
description = #{description,jdbcType=VARCHAR},
|
description = #{description,jdbcType=VARCHAR},
|
||||||
</if>
|
</if>
|
||||||
|
<if test="pos != null">
|
||||||
|
pos = #{pos,jdbcType=BIGINT},
|
||||||
|
</if>
|
||||||
</set>
|
</set>
|
||||||
where id = #{id,jdbcType=VARCHAR}
|
where id = #{id,jdbcType=VARCHAR}
|
||||||
</update>
|
</update>
|
||||||
|
@ -450,14 +464,15 @@
|
||||||
planned_end_time = #{plannedEndTime,jdbcType=BIGINT},
|
planned_end_time = #{plannedEndTime,jdbcType=BIGINT},
|
||||||
actual_start_time = #{actualStartTime,jdbcType=BIGINT},
|
actual_start_time = #{actualStartTime,jdbcType=BIGINT},
|
||||||
actual_end_time = #{actualEndTime,jdbcType=BIGINT},
|
actual_end_time = #{actualEndTime,jdbcType=BIGINT},
|
||||||
description = #{description,jdbcType=VARCHAR}
|
description = #{description,jdbcType=VARCHAR},
|
||||||
|
pos = #{pos,jdbcType=BIGINT}
|
||||||
where id = #{id,jdbcType=VARCHAR}
|
where id = #{id,jdbcType=VARCHAR}
|
||||||
</update>
|
</update>
|
||||||
<insert id="batchInsert" parameterType="map">
|
<insert id="batchInsert" parameterType="map">
|
||||||
insert into test_plan
|
insert into test_plan
|
||||||
(id, num, project_id, group_id, module_id, `name`, `status`, `type`, tags, create_time,
|
(id, num, project_id, group_id, module_id, `name`, `status`, `type`, tags, create_time,
|
||||||
create_user, update_time, update_user, planned_start_time, planned_end_time, actual_start_time,
|
create_user, update_time, update_user, planned_start_time, planned_end_time, actual_start_time,
|
||||||
actual_end_time, description)
|
actual_end_time, description, pos)
|
||||||
values
|
values
|
||||||
<foreach collection="list" item="item" separator=",">
|
<foreach collection="list" item="item" separator=",">
|
||||||
(#{item.id,jdbcType=VARCHAR}, #{item.num,jdbcType=BIGINT}, #{item.projectId,jdbcType=VARCHAR},
|
(#{item.id,jdbcType=VARCHAR}, #{item.num,jdbcType=BIGINT}, #{item.projectId,jdbcType=VARCHAR},
|
||||||
|
@ -466,7 +481,8 @@
|
||||||
#{item.createTime,jdbcType=BIGINT}, #{item.createUser,jdbcType=VARCHAR}, #{item.updateTime,jdbcType=BIGINT},
|
#{item.createTime,jdbcType=BIGINT}, #{item.createUser,jdbcType=VARCHAR}, #{item.updateTime,jdbcType=BIGINT},
|
||||||
#{item.updateUser,jdbcType=VARCHAR}, #{item.plannedStartTime,jdbcType=BIGINT},
|
#{item.updateUser,jdbcType=VARCHAR}, #{item.plannedStartTime,jdbcType=BIGINT},
|
||||||
#{item.plannedEndTime,jdbcType=BIGINT}, #{item.actualStartTime,jdbcType=BIGINT},
|
#{item.plannedEndTime,jdbcType=BIGINT}, #{item.actualStartTime,jdbcType=BIGINT},
|
||||||
#{item.actualEndTime,jdbcType=BIGINT}, #{item.description,jdbcType=VARCHAR})
|
#{item.actualEndTime,jdbcType=BIGINT}, #{item.description,jdbcType=VARCHAR}, #{item.pos,jdbcType=BIGINT}
|
||||||
|
)
|
||||||
</foreach>
|
</foreach>
|
||||||
</insert>
|
</insert>
|
||||||
<insert id="batchInsertSelective" parameterType="map">
|
<insert id="batchInsertSelective" parameterType="map">
|
||||||
|
@ -533,6 +549,9 @@
|
||||||
<if test="'description'.toString() == column.value">
|
<if test="'description'.toString() == column.value">
|
||||||
#{item.description,jdbcType=VARCHAR}
|
#{item.description,jdbcType=VARCHAR}
|
||||||
</if>
|
</if>
|
||||||
|
<if test="'pos'.toString() == column.value">
|
||||||
|
#{item.pos,jdbcType=BIGINT}
|
||||||
|
</if>
|
||||||
</foreach>
|
</foreach>
|
||||||
)
|
)
|
||||||
</foreach>
|
</foreach>
|
||||||
|
|
|
@ -11,6 +11,10 @@ CREATE TABLE IF NOT EXISTS platform_source(
|
||||||
DEFAULT CHARSET = utf8mb4
|
DEFAULT CHARSET = utf8mb4
|
||||||
COLLATE = utf8mb4_general_ci COMMENT = '平台对接保存参数';
|
COLLATE = utf8mb4_general_ci COMMENT = '平台对接保存参数';
|
||||||
|
|
||||||
|
-- 测试计划增加排序字段
|
||||||
|
alter table test_plan
|
||||||
|
ADD COLUMN `pos` BIGINT NOT NULL DEFAULT 0 COMMENT '自定义排序';
|
||||||
|
|
||||||
-- 修改计划配置表
|
-- 修改计划配置表
|
||||||
ALTER TABLE test_plan_config DROP `test_planning`;
|
ALTER TABLE test_plan_config DROP `test_planning`;
|
||||||
|
|
||||||
|
|
|
@ -86,11 +86,25 @@ test_plan_principal.user_id.not_blank=用户id不能为空
|
||||||
test_plan_report_content.id.not_blank=测试计划报告内容id不能为空
|
test_plan_report_content.id.not_blank=测试计划报告内容id不能为空
|
||||||
test_plan_report_content.test_plan_report_id.length_range=测试计划报告id长度过长
|
test_plan_report_content.test_plan_report_id.length_range=测试计划报告id长度过长
|
||||||
test_plan_report_content.test_plan_report_id.not_blank=测试计划报告id不能为空
|
test_plan_report_content.test_plan_report_id.not_blank=测试计划报告id不能为空
|
||||||
|
log.delete.test_plan=删除测试计划
|
||||||
|
log.delete.test_plan_group=删除测试计划组
|
||||||
|
log.test_plan.add=关联了资源
|
||||||
|
log.test_plan.remove=移除了资源
|
||||||
|
log.test_plan.move=移动了资源
|
||||||
|
log.test_plan.move.test_plan=移动了测试计划
|
||||||
|
log.test_plan.update=修改了资源
|
||||||
|
log.test_plan.functional_case=功能用例
|
||||||
|
log.test_plan.api_case=接口用例
|
||||||
|
log.test_plan.api_scenario=接口场景
|
||||||
|
test_plan.type.not_blank=测试计划类型不能为空
|
||||||
|
test_plan.group.not_plan=当前测试计划组没有可归档计划
|
||||||
|
test_plan.group.error=不是合法的测试计划组
|
||||||
test_plan_group.batch.log={0}测试计划组
|
test_plan_group.batch.log={0}测试计划组
|
||||||
test_plan.batch.log={0}测试计划
|
test_plan.batch.log={0}测试计划
|
||||||
test_plan_report_not_exist=测试计划报告不存在
|
test_plan_report_not_exist=测试计划报告不存在
|
||||||
test_plan_report_id.not_blank=测试计划报告id不能为空
|
test_plan_report_id.not_blank=测试计划报告id不能为空
|
||||||
test_plan_report_name.not_blank=测试计划报告名称不能为空
|
test_plan_report_name.not_blank=测试计划报告名称不能为空
|
||||||
|
run_functional_case=执行功能用例
|
||||||
test_plan_not_exist=测试计划不存在
|
test_plan_not_exist=测试计划不存在
|
||||||
test_plan.report_id.not_blank=测试计划报告ID不能为空
|
test_plan.report_id.not_blank=测试计划报告ID不能为空
|
||||||
test_plan.report.share_id.not_blank=测试计划报告分享ID不能为空
|
test_plan.report.share_id.not_blank=测试计划报告分享ID不能为空
|
||||||
|
|
|
@ -91,12 +91,14 @@ log.delete.test_plan_group=Test plan group deleted
|
||||||
log.test_plan.add=Association resources
|
log.test_plan.add=Association resources
|
||||||
log.test_plan.remove=Remove resource
|
log.test_plan.remove=Remove resource
|
||||||
log.test_plan.move=Move resources
|
log.test_plan.move=Move resources
|
||||||
|
log.test_plan.move.test_plan=Move test plan
|
||||||
log.test_plan.update=Update resources
|
log.test_plan.update=Update resources
|
||||||
log.test_plan.functional_case=Functional case
|
log.test_plan.functional_case=Functional case
|
||||||
log.test_plan.api_case=Api case
|
log.test_plan.api_case=Api case
|
||||||
log.test_plan.api_scenario=Api scenario
|
log.test_plan.api_scenario=Api scenario
|
||||||
test_plan.type.not_blank=Test plan type cannot be empty
|
test_plan.type.not_blank=Test plan type cannot be empty
|
||||||
test_plan.group.not_plan=There are no archived plans in the current testing plan group
|
test_plan.group.not_plan=There are no archived plans in the current testing plan group
|
||||||
|
test_plan.group.error=Test plan group error
|
||||||
test_plan_group.batch.log={0} test plan group
|
test_plan_group.batch.log={0} test plan group
|
||||||
test_plan.batch.log={0} plan
|
test_plan.batch.log={0} plan
|
||||||
test_plan_report_not_exist=The test plan report does not exist
|
test_plan_report_not_exist=The test plan report does not exist
|
||||||
|
|
|
@ -91,12 +91,14 @@ log.delete.test_plan_group=删除测试计划组
|
||||||
log.test_plan.add=关联了资源
|
log.test_plan.add=关联了资源
|
||||||
log.test_plan.remove=移除了资源
|
log.test_plan.remove=移除了资源
|
||||||
log.test_plan.move=移动了资源
|
log.test_plan.move=移动了资源
|
||||||
|
log.test_plan.move.test_plan=移动了测试计划
|
||||||
log.test_plan.update=修改了资源
|
log.test_plan.update=修改了资源
|
||||||
log.test_plan.functional_case=功能用例
|
log.test_plan.functional_case=功能用例
|
||||||
log.test_plan.api_case=接口用例
|
log.test_plan.api_case=接口用例
|
||||||
log.test_plan.api_scenario=接口场景
|
log.test_plan.api_scenario=接口场景
|
||||||
test_plan.type.not_blank=测试计划类型不能为空
|
test_plan.type.not_blank=测试计划类型不能为空
|
||||||
test_plan.group.not_plan=当前测试计划组没有可归档计划
|
test_plan.group.not_plan=当前测试计划组没有可归档计划
|
||||||
|
test_plan.group.error=不是合法的测试计划组
|
||||||
test_plan_group.batch.log={0}测试计划组
|
test_plan_group.batch.log={0}测试计划组
|
||||||
test_plan.batch.log={0}测试计划
|
test_plan.batch.log={0}测试计划
|
||||||
test_plan_report_not_exist=测试计划报告不存在
|
test_plan_report_not_exist=测试计划报告不存在
|
||||||
|
|
|
@ -91,12 +91,14 @@ log.delete.test_plan_group=刪除測試計劃組
|
||||||
log.test_plan.add=關聯了資源
|
log.test_plan.add=關聯了資源
|
||||||
log.test_plan.remove=移除了資源
|
log.test_plan.remove=移除了資源
|
||||||
log.test_plan.move=移動了資源
|
log.test_plan.move=移動了資源
|
||||||
|
log.test_plan.move.test_plan=移動了測試計劃
|
||||||
log.test_plan.update=修改了資源
|
log.test_plan.update=修改了資源
|
||||||
log.test_plan.functional_case=功能用例
|
log.test_plan.functional_case=功能用例
|
||||||
log.test_plan.api_case=接口用例
|
log.test_plan.api_case=接口用例
|
||||||
log.test_plan.api_scenario=接口場景
|
log.test_plan.api_scenario=接口場景
|
||||||
test_plan.type.not_blank=測試計劃類型不能為空
|
test_plan.type.not_blank=測試計劃類型不能為空
|
||||||
test_plan.group.not_plan=當前測試計劃組沒有可歸檔計劃
|
test_plan.group.not_plan=當前測試計劃組沒有可歸檔計劃
|
||||||
|
test_plan.group.error=不是合法的測試計劃組
|
||||||
test_plan_group.batch.log={0}測試計劃組
|
test_plan_group.batch.log={0}測試計劃組
|
||||||
test_plan.batch.log={0}測試計劃
|
test_plan.batch.log={0}測試計劃
|
||||||
test_plan_report_not_exist=測試計劃報告不存在
|
test_plan_report_not_exist=測試計劃報告不存在
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package io.metersphere.api.service.debug;
|
package io.metersphere.api.service.debug;
|
||||||
|
|
||||||
import io.metersphere.sdk.constants.ApiFileResourceType;
|
|
||||||
import io.metersphere.api.constants.ApiResourceType;
|
import io.metersphere.api.constants.ApiResourceType;
|
||||||
import io.metersphere.api.domain.ApiDebug;
|
import io.metersphere.api.domain.ApiDebug;
|
||||||
import io.metersphere.api.domain.ApiDebugBlob;
|
import io.metersphere.api.domain.ApiDebugBlob;
|
||||||
|
@ -24,6 +23,7 @@ import io.metersphere.project.domain.FileMetadata;
|
||||||
import io.metersphere.project.dto.MoveNodeSortDTO;
|
import io.metersphere.project.dto.MoveNodeSortDTO;
|
||||||
import io.metersphere.project.service.MoveNodeService;
|
import io.metersphere.project.service.MoveNodeService;
|
||||||
import io.metersphere.project.service.ProjectService;
|
import io.metersphere.project.service.ProjectService;
|
||||||
|
import io.metersphere.sdk.constants.ApiFileResourceType;
|
||||||
import io.metersphere.sdk.constants.DefaultRepositoryDir;
|
import io.metersphere.sdk.constants.DefaultRepositoryDir;
|
||||||
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
|
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
|
||||||
import io.metersphere.sdk.exception.MSException;
|
import io.metersphere.sdk.exception.MSException;
|
||||||
|
@ -265,7 +265,7 @@ public class ApiDebugService extends MoveNodeService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void moveNode(PosRequest posRequest) {
|
public void moveNode(PosRequest posRequest) {
|
||||||
NodeMoveRequest request = super.getNodeMoveRequest(posRequest);
|
NodeMoveRequest request = super.getNodeMoveRequest(posRequest, true);
|
||||||
MoveNodeSortDTO sortDTO = super.getNodeSortDTO(
|
MoveNodeSortDTO sortDTO = super.getNodeSortDTO(
|
||||||
posRequest.getProjectId(),
|
posRequest.getProjectId(),
|
||||||
request,
|
request,
|
||||||
|
|
|
@ -25,7 +25,10 @@ import io.metersphere.project.mapper.ExtBaseProjectVersionMapper;
|
||||||
import io.metersphere.project.service.EnvironmentService;
|
import io.metersphere.project.service.EnvironmentService;
|
||||||
import io.metersphere.project.service.MoveNodeService;
|
import io.metersphere.project.service.MoveNodeService;
|
||||||
import io.metersphere.project.service.ProjectService;
|
import io.metersphere.project.service.ProjectService;
|
||||||
import io.metersphere.sdk.constants.*;
|
import io.metersphere.sdk.constants.ApiFileResourceType;
|
||||||
|
import io.metersphere.sdk.constants.ApplicationNumScope;
|
||||||
|
import io.metersphere.sdk.constants.DefaultRepositoryDir;
|
||||||
|
import io.metersphere.sdk.constants.ModuleConstants;
|
||||||
import io.metersphere.sdk.domain.OperationLogBlob;
|
import io.metersphere.sdk.domain.OperationLogBlob;
|
||||||
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
|
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
|
||||||
import io.metersphere.sdk.exception.MSException;
|
import io.metersphere.sdk.exception.MSException;
|
||||||
|
@ -1062,7 +1065,7 @@ public class ApiDefinitionService extends MoveNodeService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void moveNode(PosRequest posRequest) {
|
public void moveNode(PosRequest posRequest) {
|
||||||
NodeMoveRequest request = super.getNodeMoveRequest(posRequest);
|
NodeMoveRequest request = super.getNodeMoveRequest(posRequest, true);
|
||||||
MoveNodeSortDTO sortDTO = super.getNodeSortDTO(
|
MoveNodeSortDTO sortDTO = super.getNodeSortDTO(
|
||||||
posRequest.getProjectId(),
|
posRequest.getProjectId(),
|
||||||
request,
|
request,
|
||||||
|
|
|
@ -826,7 +826,7 @@ public class ApiTestCaseService extends MoveNodeService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void moveNode(PosRequest posRequest) {
|
public void moveNode(PosRequest posRequest) {
|
||||||
NodeMoveRequest request = super.getNodeMoveRequest(posRequest);
|
NodeMoveRequest request = super.getNodeMoveRequest(posRequest,true);
|
||||||
MoveNodeSortDTO sortDTO = super.getNodeSortDTO(
|
MoveNodeSortDTO sortDTO = super.getNodeSortDTO(
|
||||||
posRequest.getProjectId(),
|
posRequest.getProjectId(),
|
||||||
request,
|
request,
|
||||||
|
|
|
@ -2997,7 +2997,7 @@ public class ApiScenarioService extends MoveNodeService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void moveNode(PosRequest posRequest) {
|
public void moveNode(PosRequest posRequest) {
|
||||||
NodeMoveRequest request = super.getNodeMoveRequest(posRequest);
|
NodeMoveRequest request = super.getNodeMoveRequest(posRequest, true);
|
||||||
MoveNodeSortDTO sortDTO = super.getNodeSortDTO(
|
MoveNodeSortDTO sortDTO = super.getNodeSortDTO(
|
||||||
posRequest.getProjectId(),
|
posRequest.getProjectId(),
|
||||||
request,
|
request,
|
||||||
|
|
|
@ -7,8 +7,8 @@ import lombok.Data;
|
||||||
@Data
|
@Data
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class MoveNodeSortDTO {
|
public class MoveNodeSortDTO {
|
||||||
@Schema(description = "项目ID")
|
@Schema(description = "排序范围ID")
|
||||||
private String projectId;
|
private String sortRangeId;
|
||||||
|
|
||||||
@Schema(description = "要排序的节点")
|
@Schema(description = "要排序的节点")
|
||||||
private DropNode sortNode;
|
private DropNode sortNode;
|
||||||
|
@ -18,6 +18,4 @@ public class MoveNodeSortDTO {
|
||||||
|
|
||||||
@Schema(description = "后一个节点")
|
@Schema(description = "后一个节点")
|
||||||
private DropNode nextNode;
|
private DropNode nextNode;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -273,7 +273,7 @@ public class EnvironmentGroupService extends MoveNodeService{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void moveNode(PosRequest posRequest) {
|
public void moveNode(PosRequest posRequest) {
|
||||||
NodeMoveRequest request = super.getNodeMoveRequest(posRequest);
|
NodeMoveRequest request = super.getNodeMoveRequest(posRequest, true);
|
||||||
MoveNodeSortDTO sortDTO = super.getNodeSortDTO(
|
MoveNodeSortDTO sortDTO = super.getNodeSortDTO(
|
||||||
posRequest.getProjectId(),
|
posRequest.getProjectId(),
|
||||||
request,
|
request,
|
||||||
|
|
|
@ -564,7 +564,7 @@ public class EnvironmentService extends MoveNodeService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void moveNode(PosRequest posRequest) {
|
public void moveNode(PosRequest posRequest) {
|
||||||
NodeMoveRequest request = super.getNodeMoveRequest(posRequest);
|
NodeMoveRequest request = super.getNodeMoveRequest(posRequest,true);
|
||||||
MoveNodeSortDTO sortDTO = super.getNodeSortDTO(
|
MoveNodeSortDTO sortDTO = super.getNodeSortDTO(
|
||||||
posRequest.getProjectId(),
|
posRequest.getProjectId(),
|
||||||
request,
|
request,
|
||||||
|
|
|
@ -27,9 +27,6 @@ public abstract class ModuleTreeService {
|
||||||
|
|
||||||
protected static final long LIMIT_POS = NodeSortUtils.DEFAULT_NODE_INTERVAL_POS;
|
protected static final long LIMIT_POS = NodeSortUtils.DEFAULT_NODE_INTERVAL_POS;
|
||||||
|
|
||||||
//默认节点所在分支最大数量不超过200, 后续会根据需求排期进行调整
|
|
||||||
protected static final int MAX_BRANCHES_NODE_SIZE = 200;
|
|
||||||
|
|
||||||
public BaseTreeNode getDefaultModule(String name) {
|
public BaseTreeNode getDefaultModule(String name) {
|
||||||
//默认模块下不允许创建子模块。 它本身也就是叶子节点。
|
//默认模块下不允许创建子模块。 它本身也就是叶子节点。
|
||||||
return new BaseTreeNode(ModuleConstants.DEFAULT_NODE_ID, name, ModuleConstants.NODE_TYPE_DEFAULT, ModuleConstants.ROOT_NODE_PARENT_ID);
|
return new BaseTreeNode(ModuleConstants.DEFAULT_NODE_ID, name, ModuleConstants.NODE_TYPE_DEFAULT, ModuleConstants.ROOT_NODE_PARENT_ID);
|
||||||
|
|
|
@ -7,7 +7,6 @@ import io.metersphere.project.dto.NodeSortQueryParam;
|
||||||
import io.metersphere.project.utils.NodeSortUtils;
|
import io.metersphere.project.utils.NodeSortUtils;
|
||||||
import io.metersphere.sdk.exception.MSException;
|
import io.metersphere.sdk.exception.MSException;
|
||||||
import io.metersphere.sdk.util.Translator;
|
import io.metersphere.sdk.util.Translator;
|
||||||
import io.metersphere.system.dto.sdk.enums.MoveTypeEnum;
|
|
||||||
import io.metersphere.system.dto.sdk.request.NodeMoveRequest;
|
import io.metersphere.system.dto.sdk.request.NodeMoveRequest;
|
||||||
import io.metersphere.system.dto.sdk.request.PosRequest;
|
import io.metersphere.system.dto.sdk.request.PosRequest;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
@ -28,23 +27,29 @@ public abstract class MoveNodeService {
|
||||||
private static final String MOVE_POS_OPERATOR_MORE = "moreThan";
|
private static final String MOVE_POS_OPERATOR_MORE = "moreThan";
|
||||||
private static final String DRAG_NODE_NOT_EXIST = "drag_node.not.exist";
|
private static final String DRAG_NODE_NOT_EXIST = "drag_node.not.exist";
|
||||||
|
|
||||||
public NodeMoveRequest getNodeMoveRequest(PosRequest posRequest) {
|
/**
|
||||||
|
* 构建节点移动的请求参数
|
||||||
|
*
|
||||||
|
* @param posRequest 拖拽的前端请求参数
|
||||||
|
* @param isDesc 是否是降序排列
|
||||||
|
*/
|
||||||
|
public NodeMoveRequest getNodeMoveRequest(PosRequest posRequest, boolean isDesc) {
|
||||||
NodeMoveRequest request = new NodeMoveRequest();
|
NodeMoveRequest request = new NodeMoveRequest();
|
||||||
request.setDragNodeId(posRequest.getMoveId());
|
request.setDragNodeId(posRequest.getMoveId());
|
||||||
request.setDropNodeId(posRequest.getTargetId());
|
request.setDropNodeId(posRequest.getTargetId());
|
||||||
request.setDropPosition(StringUtils.equals(MoveTypeEnum.AFTER.name(), posRequest.getMoveMode()) ? -1 : 1);
|
request.setAndConvertDropPosition(posRequest.getMoveMode(), isDesc);
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建节点排序的参数
|
* 构建节点排序的参数
|
||||||
*
|
*
|
||||||
|
* @param sortRangeId 排序范围ID
|
||||||
* @param request 拖拽的前端请求参数
|
* @param request 拖拽的前端请求参数
|
||||||
* @param selectIdNodeFunc 通过id查询节点的函数
|
* @param selectIdNodeFunc 通过id查询节点的函数
|
||||||
* @param selectPosNodeFunc 通过parentId和pos运算符查询节点的函数
|
* @param selectPosNodeFunc 通过parentId和pos运算符查询节点的函数
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
public MoveNodeSortDTO getNodeSortDTO(String projectId , NodeMoveRequest request, Function<String, DropNode> selectIdNodeFunc, Function<NodeSortQueryParam, DropNode> selectPosNodeFunc) {
|
public MoveNodeSortDTO getNodeSortDTO(String sortRangeId, NodeMoveRequest request, Function<String, DropNode> selectIdNodeFunc, Function<NodeSortQueryParam, DropNode> selectPosNodeFunc) {
|
||||||
if (StringUtils.equals(request.getDragNodeId(), request.getDropNodeId())) {
|
if (StringUtils.equals(request.getDragNodeId(), request.getDropNodeId())) {
|
||||||
//两种节点不能一样
|
//两种节点不能一样
|
||||||
throw new MSException(Translator.get("invalid_parameter") + ": drag node and drop node");
|
throw new MSException(Translator.get("invalid_parameter") + ": drag node and drop node");
|
||||||
|
@ -69,7 +74,7 @@ public abstract class MoveNodeService {
|
||||||
NodeSortQueryParam sortParam = new NodeSortQueryParam();
|
NodeSortQueryParam sortParam = new NodeSortQueryParam();
|
||||||
sortParam.setPos(previousNode.getPos());
|
sortParam.setPos(previousNode.getPos());
|
||||||
sortParam.setOperator(MOVE_POS_OPERATOR_MORE);
|
sortParam.setOperator(MOVE_POS_OPERATOR_MORE);
|
||||||
sortParam.setParentId(projectId);
|
sortParam.setParentId(sortRangeId);
|
||||||
nextNode = selectPosNodeFunc.apply(sortParam);
|
nextNode = selectPosNodeFunc.apply(sortParam);
|
||||||
} else if (request.getDropPosition() == -1) {
|
} else if (request.getDropPosition() == -1) {
|
||||||
//dropPosition=-1: 放到dropNode节点前,原dropNode前面的节点之后
|
//dropPosition=-1: 放到dropNode节点前,原dropNode前面的节点之后
|
||||||
|
@ -77,29 +82,26 @@ public abstract class MoveNodeService {
|
||||||
NodeSortQueryParam sortParam = new NodeSortQueryParam();
|
NodeSortQueryParam sortParam = new NodeSortQueryParam();
|
||||||
sortParam.setPos(nextNode.getPos());
|
sortParam.setPos(nextNode.getPos());
|
||||||
sortParam.setOperator(MOVE_POS_OPERATOR_LESS);
|
sortParam.setOperator(MOVE_POS_OPERATOR_LESS);
|
||||||
sortParam.setParentId(projectId);
|
sortParam.setParentId(sortRangeId);
|
||||||
previousNode = selectPosNodeFunc.apply(sortParam);
|
previousNode = selectPosNodeFunc.apply(sortParam);
|
||||||
} else {
|
} else {
|
||||||
throw new MSException(Translator.get("invalid_parameter") + ": dropPosition");
|
throw new MSException(Translator.get("invalid_parameter") + ": dropPosition");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new MoveNodeSortDTO(projectId, dragNode, previousNode, nextNode);
|
return new MoveNodeSortDTO(sortRangeId, dragNode, previousNode, nextNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
//排序
|
//排序
|
||||||
public void sort(MoveNodeSortDTO sortDTO) {
|
public void sort(MoveNodeSortDTO sortDTO) {
|
||||||
|
|
||||||
// 获取相邻节点
|
// 获取相邻节点
|
||||||
DropNode previousNode = sortDTO.getPreviousNode();
|
DropNode previousNode = sortDTO.getPreviousNode();
|
||||||
DropNode nextNode = sortDTO.getNextNode();
|
DropNode nextNode = sortDTO.getNextNode();
|
||||||
|
|
||||||
ModuleSortCountResultDTO countResultDTO = NodeSortUtils.countModuleSort(
|
ModuleSortCountResultDTO countResultDTO = NodeSortUtils.countModuleSort(
|
||||||
previousNode == null ? -1 : previousNode.getPos(),
|
previousNode == null ? -1 : previousNode.getPos(),
|
||||||
nextNode == null ? -1 : nextNode.getPos());
|
nextNode == null ? -1 : nextNode.getPos());
|
||||||
|
|
||||||
updatePos(sortDTO.getSortNode().getId(), countResultDTO.getPos());
|
updatePos(sortDTO.getSortNode().getId(), countResultDTO.getPos());
|
||||||
if (countResultDTO.isRefreshPos()) {
|
if (countResultDTO.isRefreshPos()) {
|
||||||
refreshPos(sortDTO.getProjectId());
|
refreshPos(sortDTO.getSortRangeId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import io.metersphere.project.dto.ModuleSortCountResultDTO;
|
||||||
public class NodeSortUtils {
|
public class NodeSortUtils {
|
||||||
|
|
||||||
//默认节点间隔
|
//默认节点间隔
|
||||||
public static final long DEFAULT_NODE_INTERVAL_POS = 64;
|
public static final long DEFAULT_NODE_INTERVAL_POS = 4096;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算模块排序
|
* 计算模块排序
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
package io.metersphere.system.dto.sdk.request;
|
package io.metersphere.system.dto.sdk.request;
|
||||||
|
|
||||||
|
import io.metersphere.system.dto.sdk.enums.MoveTypeEnum;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import jakarta.validation.constraints.NotEmpty;
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class NodeMoveRequest {
|
public class NodeMoveRequest {
|
||||||
|
@ -16,5 +18,13 @@ public class NodeMoveRequest {
|
||||||
|
|
||||||
@Schema(description = "放入的位置(取值:-1,,1。 -1:dropNodeId节点之前。 1:dropNodeId节点后)", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "放入的位置(取值:-1,,1。 -1:dropNodeId节点之前。 1:dropNodeId节点后)", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private int dropPosition;
|
private int dropPosition;
|
||||||
|
|
||||||
|
public void setAndConvertDropPosition(String position, boolean isSortDesc) {
|
||||||
|
if (StringUtils.equals(MoveTypeEnum.BEFORE.name(), position)) {
|
||||||
|
this.dropPosition = isSortDesc ? 1 : -1;
|
||||||
|
} else {
|
||||||
|
this.dropPosition = isSortDesc ? -1 : 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,10 @@ package io.metersphere.system.dto.sdk.request;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
@ -13,6 +15,8 @@ import java.io.Serializable;
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
public class PosRequest implements Serializable {
|
public class PosRequest implements Serializable {
|
||||||
|
|
||||||
@Serial
|
@Serial
|
||||||
|
@ -22,6 +26,10 @@ public class PosRequest implements Serializable {
|
||||||
@NotBlank(message = "{case_review.project_id.not_blank}")
|
@NotBlank(message = "{case_review.project_id.not_blank}")
|
||||||
private String projectId;
|
private String projectId;
|
||||||
|
|
||||||
|
@Schema(description = "移动用例id", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@NotBlank(message = "{functional_case_relationship_edge.source_id.not_blank}")
|
||||||
|
private String moveId;
|
||||||
|
|
||||||
@Schema(description = "目标用例id", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "目标用例id", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
@NotBlank(message = "{functional_case_relationship_edge.target_id.not_blank}")
|
@NotBlank(message = "{functional_case_relationship_edge.target_id.not_blank}")
|
||||||
private String targetId;
|
private String targetId;
|
||||||
|
@ -29,8 +37,4 @@ public class PosRequest implements Serializable {
|
||||||
@Schema(description = "移动类型", requiredMode = Schema.RequiredMode.REQUIRED, allowableValues = {"BEFORE", "AFTER", "APPEND"})
|
@Schema(description = "移动类型", requiredMode = Schema.RequiredMode.REQUIRED, allowableValues = {"BEFORE", "AFTER", "APPEND"})
|
||||||
@NotBlank(message = "{case_review.moveMode.not_blank}")
|
@NotBlank(message = "{case_review.moveMode.not_blank}")
|
||||||
private String moveMode;
|
private String moveMode;
|
||||||
|
|
||||||
@Schema(description = "移动用例id", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@NotBlank(message = "{functional_case_relationship_edge.source_id.not_blank}")
|
|
||||||
private String moveId;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,14 @@ import io.metersphere.plan.constants.TestPlanResourceConfig;
|
||||||
import io.metersphere.plan.domain.TestPlan;
|
import io.metersphere.plan.domain.TestPlan;
|
||||||
import io.metersphere.plan.dto.request.*;
|
import io.metersphere.plan.dto.request.*;
|
||||||
import io.metersphere.plan.dto.response.TestPlanDetailResponse;
|
import io.metersphere.plan.dto.response.TestPlanDetailResponse;
|
||||||
|
import io.metersphere.plan.dto.response.TestPlanResourceSortResponse;
|
||||||
import io.metersphere.plan.dto.response.TestPlanResponse;
|
import io.metersphere.plan.dto.response.TestPlanResponse;
|
||||||
import io.metersphere.plan.dto.response.TestPlanStatisticsResponse;
|
import io.metersphere.plan.dto.response.TestPlanStatisticsResponse;
|
||||||
import io.metersphere.plan.service.*;
|
import io.metersphere.plan.service.*;
|
||||||
import io.metersphere.sdk.constants.HttpMethodConstants;
|
import io.metersphere.sdk.constants.HttpMethodConstants;
|
||||||
import io.metersphere.sdk.constants.PermissionConstants;
|
import io.metersphere.sdk.constants.PermissionConstants;
|
||||||
|
import io.metersphere.system.dto.LogInsertModule;
|
||||||
|
import io.metersphere.system.dto.sdk.request.PosRequest;
|
||||||
import io.metersphere.system.log.annotation.Log;
|
import io.metersphere.system.log.annotation.Log;
|
||||||
import io.metersphere.system.log.constants.OperationLogType;
|
import io.metersphere.system.log.constants.OperationLogType;
|
||||||
import io.metersphere.system.notice.annotation.SendNotice;
|
import io.metersphere.system.notice.annotation.SendNotice;
|
||||||
|
@ -193,4 +196,13 @@ public class TestPlanController {
|
||||||
testPlanService.filterArchivedIds(request);
|
testPlanService.filterArchivedIds(request);
|
||||||
testPlanService.batchEdit(request, SessionUtils.getUserId());
|
testPlanService.batchEdit(request, SessionUtils.getUserId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = "/sort")
|
||||||
|
@Operation(summary = "测试计划移动(测试计划拖进、拖出到测试计划组、测试计划在测试计划组内的排序")
|
||||||
|
@RequiresPermissions(PermissionConstants.TEST_PLAN_READ_UPDATE)
|
||||||
|
@CheckOwner(resourceId = "#request.getMoveId()", resourceType = "test_plan")
|
||||||
|
public TestPlanResourceSortResponse sortTestPlan(@Validated @RequestBody PosRequest request) {
|
||||||
|
testPlanManagementService.checkModuleIsOpen(request.getMoveId(), TestPlanResourceConfig.CHECK_TYPE_TEST_PLAN, Collections.singletonList(TestPlanResourceConfig.CONFIG_TEST_PLAN));
|
||||||
|
return testPlanService.sortInGroup(request, new LogInsertModule(SessionUtils.getUserId(), "/test-plan/move", HttpMethodConstants.POST.name()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
package io.metersphere.plan.dto;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class AssociationNode {
|
|
||||||
private String id;
|
|
||||||
private long pos;
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
package io.metersphere.plan.dto;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class AssociationNodeSortDTO {
|
|
||||||
@Schema(description = "测试计划ID")
|
|
||||||
private String testPlanId;
|
|
||||||
|
|
||||||
@Schema(description = "要排序的节点")
|
|
||||||
private AssociationNode sortNode;
|
|
||||||
|
|
||||||
@Schema(description = "前一个节点")
|
|
||||||
private AssociationNode previousNode;
|
|
||||||
|
|
||||||
@Schema(description = "后一个节点")
|
|
||||||
private AssociationNode nextNode;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
package io.metersphere.plan.dto.response;
|
package io.metersphere.plan.dto.response;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
public class TestPlanResourceSortResponse {
|
public class TestPlanResourceSortResponse {
|
||||||
@Schema(description = "本次排序的数量")
|
@Schema(description = "本次排序的数量")
|
||||||
private long sortNodeNum;
|
private long sortNodeNum;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package io.metersphere.plan.mapper;
|
package io.metersphere.plan.mapper;
|
||||||
|
|
||||||
import io.metersphere.api.dto.definition.ApiDefinitionDTO;
|
import io.metersphere.api.dto.definition.ApiDefinitionDTO;
|
||||||
import io.metersphere.plan.dto.AssociationNode;
|
|
||||||
import io.metersphere.plan.dto.ResourceSelectParam;
|
import io.metersphere.plan.dto.ResourceSelectParam;
|
||||||
import io.metersphere.plan.dto.TestPlanCaseRunResultCount;
|
import io.metersphere.plan.dto.TestPlanCaseRunResultCount;
|
||||||
import io.metersphere.plan.dto.request.TestPlanApiRequest;
|
import io.metersphere.plan.dto.request.TestPlanApiRequest;
|
||||||
|
import io.metersphere.project.dto.DropNode;
|
||||||
import io.metersphere.project.dto.NodeSortQueryParam;
|
import io.metersphere.project.dto.NodeSortQueryParam;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
@ -20,9 +20,9 @@ public interface ExtTestPlanApiCaseMapper {
|
||||||
|
|
||||||
List<String> getIdByParam(ResourceSelectParam resourceSelectParam);
|
List<String> getIdByParam(ResourceSelectParam resourceSelectParam);
|
||||||
|
|
||||||
AssociationNode selectDragInfoById(String id);
|
DropNode selectDragInfoById(String id);
|
||||||
|
|
||||||
AssociationNode selectNodeByPosOperator(NodeSortQueryParam nodeSortQueryParam);
|
DropNode selectNodeByPosOperator(NodeSortQueryParam nodeSortQueryParam);
|
||||||
|
|
||||||
List<TestPlanCaseRunResultCount> selectCaseExecResultCount(String testPlanId);
|
List<TestPlanCaseRunResultCount> selectCaseExecResultCount(String testPlanId);
|
||||||
|
|
||||||
|
|
|
@ -51,14 +51,14 @@
|
||||||
</if>
|
</if>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectDragInfoById" resultType="io.metersphere.plan.dto.AssociationNode">
|
<select id="selectDragInfoById" resultType="io.metersphere.project.dto.DropNode">
|
||||||
SELECT id, pos
|
SELECT id, pos
|
||||||
FROM test_plan_api_case
|
FROM test_plan_api_case
|
||||||
WHERE id = #{0}
|
WHERE id = #{0}
|
||||||
</select>
|
</select>
|
||||||
<select id="selectNodeByPosOperator"
|
<select id="selectNodeByPosOperator"
|
||||||
parameterType="io.metersphere.project.dto.NodeSortQueryParam"
|
parameterType="io.metersphere.project.dto.NodeSortQueryParam"
|
||||||
resultType="io.metersphere.plan.dto.AssociationNode">
|
resultType="io.metersphere.project.dto.DropNode">
|
||||||
SELECT id, pos
|
SELECT id, pos
|
||||||
FROM test_plan_api_case
|
FROM test_plan_api_case
|
||||||
WHERE test_plan_id = #{parentId}
|
WHERE test_plan_id = #{parentId}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package io.metersphere.plan.mapper;
|
package io.metersphere.plan.mapper;
|
||||||
|
|
||||||
import io.metersphere.plan.dto.AssociationNode;
|
|
||||||
import io.metersphere.plan.dto.ResourceSelectParam;
|
import io.metersphere.plan.dto.ResourceSelectParam;
|
||||||
import io.metersphere.plan.dto.TestPlanCaseRunResultCount;
|
import io.metersphere.plan.dto.TestPlanCaseRunResultCount;
|
||||||
|
import io.metersphere.project.dto.DropNode;
|
||||||
import io.metersphere.project.dto.NodeSortQueryParam;
|
import io.metersphere.project.dto.NodeSortQueryParam;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
@ -18,9 +18,9 @@ public interface ExtTestPlanApiScenarioMapper {
|
||||||
|
|
||||||
List<String> getIdByParam(ResourceSelectParam resourceSelectParam);
|
List<String> getIdByParam(ResourceSelectParam resourceSelectParam);
|
||||||
|
|
||||||
AssociationNode selectDragInfoById(String id);
|
DropNode selectDragInfoById(String id);
|
||||||
|
|
||||||
AssociationNode selectNodeByPosOperator(NodeSortQueryParam nodeSortQueryParam);
|
DropNode selectNodeByPosOperator(NodeSortQueryParam nodeSortQueryParam);
|
||||||
|
|
||||||
List<TestPlanCaseRunResultCount> selectCaseExecResultCount(String testPlanId);
|
List<TestPlanCaseRunResultCount> selectCaseExecResultCount(String testPlanId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,14 +44,14 @@
|
||||||
ORDER BY #{orderString}
|
ORDER BY #{orderString}
|
||||||
</if>
|
</if>
|
||||||
</select>
|
</select>
|
||||||
<select id="selectDragInfoById" resultType="io.metersphere.plan.dto.AssociationNode">
|
<select id="selectDragInfoById" resultType="io.metersphere.project.dto.DropNode">
|
||||||
SELECT id, pos
|
SELECT id, pos
|
||||||
FROM test_plan_api_scenario
|
FROM test_plan_api_scenario
|
||||||
WHERE id = #{0}
|
WHERE id = #{0}
|
||||||
</select>
|
</select>
|
||||||
<select id="selectNodeByPosOperator"
|
<select id="selectNodeByPosOperator"
|
||||||
parameterType="io.metersphere.project.dto.NodeSortQueryParam"
|
parameterType="io.metersphere.project.dto.NodeSortQueryParam"
|
||||||
resultType="io.metersphere.plan.dto.AssociationNode">
|
resultType="io.metersphere.project.dto.DropNode">
|
||||||
SELECT id, pos
|
SELECT id, pos
|
||||||
FROM test_plan_api_scenario
|
FROM test_plan_api_scenario
|
||||||
WHERE test_plan_id = #{parentId}
|
WHERE test_plan_id = #{parentId}
|
||||||
|
|
|
@ -4,12 +4,12 @@ import io.metersphere.functional.dto.FunctionalCaseModuleCountDTO;
|
||||||
import io.metersphere.functional.dto.FunctionalCaseModuleDTO;
|
import io.metersphere.functional.dto.FunctionalCaseModuleDTO;
|
||||||
import io.metersphere.functional.dto.ProjectOptionDTO;
|
import io.metersphere.functional.dto.ProjectOptionDTO;
|
||||||
import io.metersphere.plan.domain.TestPlanFunctionalCase;
|
import io.metersphere.plan.domain.TestPlanFunctionalCase;
|
||||||
import io.metersphere.plan.dto.AssociationNode;
|
|
||||||
import io.metersphere.plan.dto.ResourceSelectParam;
|
import io.metersphere.plan.dto.ResourceSelectParam;
|
||||||
import io.metersphere.plan.dto.TestPlanCaseRunResultCount;
|
import io.metersphere.plan.dto.TestPlanCaseRunResultCount;
|
||||||
import io.metersphere.plan.dto.request.BasePlanCaseBatchRequest;
|
import io.metersphere.plan.dto.request.BasePlanCaseBatchRequest;
|
||||||
import io.metersphere.plan.dto.request.TestPlanCaseRequest;
|
import io.metersphere.plan.dto.request.TestPlanCaseRequest;
|
||||||
import io.metersphere.plan.dto.response.TestPlanCasePageResponse;
|
import io.metersphere.plan.dto.response.TestPlanCasePageResponse;
|
||||||
|
import io.metersphere.project.dto.DropNode;
|
||||||
import io.metersphere.project.dto.NodeSortQueryParam;
|
import io.metersphere.project.dto.NodeSortQueryParam;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
@ -27,9 +27,9 @@ public interface ExtTestPlanFunctionalCaseMapper {
|
||||||
|
|
||||||
List<String> getIdByParam(ResourceSelectParam resourceSelectParam);
|
List<String> getIdByParam(ResourceSelectParam resourceSelectParam);
|
||||||
|
|
||||||
AssociationNode selectDragInfoById(String id);
|
DropNode selectDragInfoById(String id);
|
||||||
|
|
||||||
AssociationNode selectNodeByPosOperator(NodeSortQueryParam nodeSortQueryParam);
|
DropNode selectNodeByPosOperator(NodeSortQueryParam nodeSortQueryParam);
|
||||||
|
|
||||||
List<TestPlanCasePageResponse> getCasePage(@Param("request") TestPlanCaseRequest request, @Param("deleted") boolean deleted, @Param("sort") String sort);
|
List<TestPlanCasePageResponse> getCasePage(@Param("request") TestPlanCaseRequest request, @Param("deleted") boolean deleted, @Param("sort") String sort);
|
||||||
|
|
||||||
|
|
|
@ -65,14 +65,14 @@
|
||||||
<include refid="queryWhereConditionByBatchQueryRequest"/>
|
<include refid="queryWhereConditionByBatchQueryRequest"/>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectDragInfoById" resultType="io.metersphere.plan.dto.AssociationNode">
|
<select id="selectDragInfoById" resultType="io.metersphere.project.dto.DropNode">
|
||||||
SELECT id, pos
|
SELECT id, pos
|
||||||
FROM test_plan_functional_case
|
FROM test_plan_functional_case
|
||||||
WHERE id = #{0}
|
WHERE id = #{0}
|
||||||
</select>
|
</select>
|
||||||
<select id="selectNodeByPosOperator"
|
<select id="selectNodeByPosOperator"
|
||||||
parameterType="io.metersphere.project.dto.NodeSortQueryParam"
|
parameterType="io.metersphere.project.dto.NodeSortQueryParam"
|
||||||
resultType="io.metersphere.plan.dto.AssociationNode">
|
resultType="io.metersphere.project.dto.DropNode">
|
||||||
SELECT id, pos
|
SELECT id, pos
|
||||||
FROM test_plan_functional_case
|
FROM test_plan_functional_case
|
||||||
WHERE test_plan_id = #{parentId}
|
WHERE test_plan_id = #{parentId}
|
||||||
|
|
|
@ -5,7 +5,9 @@ import io.metersphere.plan.dto.TestPlanQueryConditions;
|
||||||
import io.metersphere.plan.dto.request.TestPlanBatchProcessRequest;
|
import io.metersphere.plan.dto.request.TestPlanBatchProcessRequest;
|
||||||
import io.metersphere.plan.dto.request.TestPlanTableRequest;
|
import io.metersphere.plan.dto.request.TestPlanTableRequest;
|
||||||
import io.metersphere.plan.dto.response.TestPlanResponse;
|
import io.metersphere.plan.dto.response.TestPlanResponse;
|
||||||
|
import io.metersphere.project.dto.DropNode;
|
||||||
import io.metersphere.project.dto.ModuleCountDTO;
|
import io.metersphere.project.dto.ModuleCountDTO;
|
||||||
|
import io.metersphere.project.dto.NodeSortQueryParam;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -40,4 +42,10 @@ public interface ExtTestPlanMapper {
|
||||||
List<String> selectIdByProjectId(String projectId);
|
List<String> selectIdByProjectId(String projectId);
|
||||||
|
|
||||||
List<String> selectNotArchivedIds(@Param("ids") List<String> selectIds);
|
List<String> selectNotArchivedIds(@Param("ids") List<String> selectIds);
|
||||||
|
|
||||||
|
DropNode selectDragInfoById(String s);
|
||||||
|
|
||||||
|
DropNode selectNodeByPosOperator(NodeSortQueryParam nodeSortQueryParam);
|
||||||
|
|
||||||
|
long selectMaxPosByGroupId(String groupId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@
|
||||||
t.module_id as moduleId,
|
t.module_id as moduleId,
|
||||||
t.type,
|
t.type,
|
||||||
t.description,
|
t.description,
|
||||||
|
t.pos,
|
||||||
t.tags
|
t.tags
|
||||||
FROM test_plan t
|
FROM test_plan t
|
||||||
INNER JOIN user createUser ON t.create_user = createUser.id
|
INNER JOIN user createUser ON t.create_user = createUser.id
|
||||||
|
@ -63,6 +64,7 @@
|
||||||
</foreach>
|
</foreach>
|
||||||
</if>
|
</if>
|
||||||
<include refid="queryWhereCondition"/>
|
<include refid="queryWhereCondition"/>
|
||||||
|
ORDER BY t.pos ASC
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<sql id="queryWhereCondition">
|
<sql id="queryWhereCondition">
|
||||||
|
@ -90,7 +92,7 @@
|
||||||
</when>
|
</when>
|
||||||
<when test="request.type == 'GROUP'">
|
<when test="request.type == 'GROUP'">
|
||||||
and t.group_id = 'NONE'
|
and t.group_id = 'NONE'
|
||||||
and t.type = 'GTOUP'
|
and t.type = 'GROUP'
|
||||||
</when>
|
</when>
|
||||||
</choose>
|
</choose>
|
||||||
</if>
|
</if>
|
||||||
|
@ -408,7 +410,35 @@
|
||||||
</foreach>
|
</foreach>
|
||||||
AND status != 'ARCHIVED'
|
AND status != 'ARCHIVED'
|
||||||
</select>
|
</select>
|
||||||
|
<select id="selectDragInfoById" resultType="io.metersphere.project.dto.DropNode">
|
||||||
|
SELECT id, pos
|
||||||
|
FROM test_plan
|
||||||
|
WHERE id = #{0}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectNodeByPosOperator"
|
||||||
|
parameterType="io.metersphere.project.dto.NodeSortQueryParam"
|
||||||
|
resultType="io.metersphere.project.dto.DropNode">
|
||||||
|
SELECT id, pos
|
||||||
|
FROM test_plan
|
||||||
|
WHERE group_id = #{parentId}
|
||||||
|
<if test="operator == 'moreThan'">
|
||||||
|
AND pos > #{pos}
|
||||||
|
</if>
|
||||||
|
<if test="operator == 'lessThan'">
|
||||||
|
AND pos < #{pos}
|
||||||
|
</if>
|
||||||
|
ORDER BY pos
|
||||||
|
<if test="operator == 'lessThan' or operator == 'latest'">
|
||||||
|
DESC
|
||||||
|
</if>
|
||||||
|
LIMIT 1
|
||||||
|
</select>
|
||||||
|
<select id="selectMaxPosByGroupId" resultType="java.lang.Long">
|
||||||
|
SELECT IF(MAX(pos) IS NULL, 0, MAX(pos)) AS pos
|
||||||
|
FROM test_plan
|
||||||
|
WHERE group_id = #{0}
|
||||||
|
</select>
|
||||||
|
|
||||||
<update id="batchUpdate">
|
<update id="batchUpdate">
|
||||||
update test_plan
|
update test_plan
|
||||||
|
|
|
@ -18,7 +18,6 @@ import io.metersphere.functional.service.FunctionalCaseAttachmentService;
|
||||||
import io.metersphere.functional.service.FunctionalCaseModuleService;
|
import io.metersphere.functional.service.FunctionalCaseModuleService;
|
||||||
import io.metersphere.functional.service.FunctionalCaseService;
|
import io.metersphere.functional.service.FunctionalCaseService;
|
||||||
import io.metersphere.plan.domain.*;
|
import io.metersphere.plan.domain.*;
|
||||||
import io.metersphere.plan.dto.AssociationNodeSortDTO;
|
|
||||||
import io.metersphere.plan.dto.ResourceLogInsertModule;
|
import io.metersphere.plan.dto.ResourceLogInsertModule;
|
||||||
import io.metersphere.plan.dto.TestPlanCaseRunResultCount;
|
import io.metersphere.plan.dto.TestPlanCaseRunResultCount;
|
||||||
import io.metersphere.plan.dto.TestPlanResourceAssociationParam;
|
import io.metersphere.plan.dto.TestPlanResourceAssociationParam;
|
||||||
|
@ -28,6 +27,7 @@ import io.metersphere.plan.mapper.*;
|
||||||
import io.metersphere.plugin.platform.dto.SelectOption;
|
import io.metersphere.plugin.platform.dto.SelectOption;
|
||||||
import io.metersphere.project.domain.Project;
|
import io.metersphere.project.domain.Project;
|
||||||
import io.metersphere.project.dto.ModuleCountDTO;
|
import io.metersphere.project.dto.ModuleCountDTO;
|
||||||
|
import io.metersphere.project.dto.MoveNodeSortDTO;
|
||||||
import io.metersphere.provider.BaseAssociateBugProvider;
|
import io.metersphere.provider.BaseAssociateBugProvider;
|
||||||
import io.metersphere.request.AssociateBugPageRequest;
|
import io.metersphere.request.AssociateBugPageRequest;
|
||||||
import io.metersphere.request.BugPageProviderRequest;
|
import io.metersphere.request.BugPageProviderRequest;
|
||||||
|
@ -171,9 +171,9 @@ public class TestPlanFunctionalCaseService extends TestPlanResourceService {
|
||||||
throw new MSException(Translator.get("test_plan.drag.node.error"));
|
throw new MSException(Translator.get("test_plan.drag.node.error"));
|
||||||
}
|
}
|
||||||
TestPlanResourceSortResponse response = new TestPlanResourceSortResponse();
|
TestPlanResourceSortResponse response = new TestPlanResourceSortResponse();
|
||||||
AssociationNodeSortDTO sortDTO = super.getNodeSortDTO(
|
MoveNodeSortDTO sortDTO = super.getNodeSortDTO(
|
||||||
super.getNodeMoveRequest(request),
|
|
||||||
request.getTestPlanId(),
|
request.getTestPlanId(),
|
||||||
|
super.getNodeMoveRequest(request, true),
|
||||||
extTestPlanFunctionalCaseMapper::selectDragInfoById,
|
extTestPlanFunctionalCaseMapper::selectDragInfoById,
|
||||||
extTestPlanFunctionalCaseMapper::selectNodeByPosOperator
|
extTestPlanFunctionalCaseMapper::selectNodeByPosOperator
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,8 +1,93 @@
|
||||||
package io.metersphere.plan.service;
|
package io.metersphere.plan.service;
|
||||||
|
|
||||||
import io.metersphere.plan.domain.TestPlan;
|
import io.metersphere.plan.domain.TestPlan;
|
||||||
import io.metersphere.plan.domain.TestPlanConfig;
|
import io.metersphere.plan.domain.TestPlanExample;
|
||||||
|
import io.metersphere.plan.mapper.ExtTestPlanMapper;
|
||||||
|
import io.metersphere.plan.mapper.TestPlanMapper;
|
||||||
|
import io.metersphere.project.dto.MoveNodeSortDTO;
|
||||||
|
import io.metersphere.sdk.constants.TestPlanConstants;
|
||||||
|
import io.metersphere.sdk.exception.MSException;
|
||||||
|
import io.metersphere.sdk.util.Translator;
|
||||||
|
import io.metersphere.system.dto.sdk.enums.MoveTypeEnum;
|
||||||
|
import io.metersphere.system.dto.sdk.request.PosRequest;
|
||||||
|
import io.metersphere.system.utils.ServiceUtils;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
public interface TestPlanGroupService {
|
import java.util.List;
|
||||||
boolean validateGroup(TestPlan testPlan, TestPlanConfig testPlanConfig);
|
|
||||||
|
@Service
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public class TestPlanGroupService extends TestPlanSortService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TestPlanMapper testPlanMapper;
|
||||||
|
@Resource
|
||||||
|
private ExtTestPlanMapper extTestPlanMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getNextOrder(String groupId) {
|
||||||
|
long maxPos = extTestPlanMapper.selectMaxPosByGroupId(groupId);
|
||||||
|
return maxPos + ServiceUtils.POS_STEP;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updatePos(String id, long pos) {
|
||||||
|
TestPlan testPlan = new TestPlan();
|
||||||
|
testPlan.setId(id);
|
||||||
|
testPlan.setPos(pos);
|
||||||
|
testPlanMapper.updateByPrimaryKeySelective(testPlan);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void refreshPos(String groupId) {
|
||||||
|
TestPlanExample testPlanExample = new TestPlanExample();
|
||||||
|
testPlanExample.createCriteria().andGroupIdEqualTo(groupId);
|
||||||
|
testPlanExample.setOrderByClause("pos asc");
|
||||||
|
List<TestPlan> testPlans = testPlanMapper.selectByExample(testPlanExample);
|
||||||
|
long pos = 1;
|
||||||
|
for (TestPlan testPlanItem : testPlans) {
|
||||||
|
this.updatePos(testPlanItem.getId(), pos * ServiceUtils.POS_STEP);
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sort(PosRequest request) {
|
||||||
|
TestPlan dropPlan = testPlanMapper.selectByPrimaryKey(request.getMoveId());
|
||||||
|
TestPlan targetPlan = testPlanMapper.selectByPrimaryKey(request.getTargetId());
|
||||||
|
|
||||||
|
// 校验排序的参数 (暂时不支持测试计划的移入移出)
|
||||||
|
validateMoveRequest(dropPlan, targetPlan, request.getMoveMode());
|
||||||
|
MoveNodeSortDTO sortDTO = super.getNodeSortDTO(
|
||||||
|
targetPlan.getGroupId(),
|
||||||
|
this.getNodeMoveRequest(request, false),
|
||||||
|
extTestPlanMapper::selectDragInfoById,
|
||||||
|
extTestPlanMapper::selectNodeByPosOperator
|
||||||
|
);
|
||||||
|
|
||||||
|
this.sort(sortDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateMoveRequest(TestPlan dropPlan, TestPlan targetPlan, String moveType) {
|
||||||
|
//测试计划组不能进行移动操作
|
||||||
|
if (dropPlan == null || StringUtils.equalsIgnoreCase(dropPlan.getType(), TestPlanConstants.TEST_PLAN_TYPE_GROUP)) {
|
||||||
|
throw new MSException(Translator.get("test_plan.drag.node.error"));
|
||||||
|
}
|
||||||
|
if (targetPlan == null || StringUtils.equalsIgnoreCase(targetPlan.getGroupId(), TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID)) {
|
||||||
|
throw new MSException(Translator.get("test_plan.drag.node.error"));
|
||||||
|
}
|
||||||
|
if (StringUtils.equalsIgnoreCase(MoveTypeEnum.APPEND.name(), moveType)) {
|
||||||
|
if (!StringUtils.equalsIgnoreCase(targetPlan.getType(), TestPlanConstants.TEST_PLAN_TYPE_GROUP)) {
|
||||||
|
throw new MSException(Translator.get("test_plan.drag.node.error"));
|
||||||
|
}
|
||||||
|
} else if (StringUtils.equalsAnyIgnoreCase(moveType, MoveTypeEnum.BEFORE.name(), MoveTypeEnum.AFTER.name())) {
|
||||||
|
if (StringUtils.equalsAny(TestPlanConstants.TEST_PLAN_TYPE_GROUP, dropPlan.getType())) {
|
||||||
|
throw new MSException(Translator.get("test_plan.drag.node.error"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new MSException(Translator.get("test_plan.drag.position.error"));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import io.metersphere.sdk.constants.HttpMethodConstants;
|
||||||
import io.metersphere.sdk.constants.TestPlanConstants;
|
import io.metersphere.sdk.constants.TestPlanConstants;
|
||||||
import io.metersphere.sdk.util.JSON;
|
import io.metersphere.sdk.util.JSON;
|
||||||
import io.metersphere.sdk.util.Translator;
|
import io.metersphere.sdk.util.Translator;
|
||||||
|
import io.metersphere.system.dto.LogInsertModule;
|
||||||
import io.metersphere.system.dto.builder.LogDTOBuilder;
|
import io.metersphere.system.dto.builder.LogDTOBuilder;
|
||||||
import io.metersphere.system.log.constants.OperationLogModule;
|
import io.metersphere.system.log.constants.OperationLogModule;
|
||||||
import io.metersphere.system.log.constants.OperationLogType;
|
import io.metersphere.system.log.constants.OperationLogType;
|
||||||
|
@ -245,4 +246,22 @@ public class TestPlanLogService {
|
||||||
}
|
}
|
||||||
return dtoList;
|
return dtoList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void saveMoveLog(TestPlan testPlan, String moveId, LogInsertModule logInsertModule) {
|
||||||
|
|
||||||
|
Project project = projectMapper.selectByPrimaryKey(testPlan.getProjectId());
|
||||||
|
LogDTO dto = LogDTOBuilder.builder()
|
||||||
|
.projectId(testPlan.getProjectId())
|
||||||
|
.organizationId(project.getOrganizationId())
|
||||||
|
.type(OperationLogType.UPDATE.name())
|
||||||
|
.module(logModule)
|
||||||
|
.method(logInsertModule.getRequestMethod())
|
||||||
|
.path(logInsertModule.getRequestUrl())
|
||||||
|
.sourceId(moveId)
|
||||||
|
.content(Translator.get("log.test_plan.move.test_plan") + ":" + testPlan.getName() + StringUtils.SPACE)
|
||||||
|
.createUser(logInsertModule.getOperator())
|
||||||
|
.build().getLogDTO();
|
||||||
|
operationLogService.add(dto);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,9 +55,6 @@ public class TestPlanManagementService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 测试计划列表查询
|
* 测试计划列表查询
|
||||||
*
|
|
||||||
* @param request
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
public Pager<List<TestPlanResponse>> page(TestPlanTableRequest request) {
|
public Pager<List<TestPlanResponse>> page(TestPlanTableRequest request) {
|
||||||
Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize(),
|
Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize(),
|
||||||
|
@ -73,8 +70,6 @@ public class TestPlanManagementService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计划组子节点
|
* 计划组子节点
|
||||||
*
|
|
||||||
* @param testPlanResponses
|
|
||||||
*/
|
*/
|
||||||
private void handChildren(List<TestPlanResponse> testPlanResponses, String projectId) {
|
private void handChildren(List<TestPlanResponse> testPlanResponses, String projectId) {
|
||||||
List<String> groupIds = testPlanResponses.stream().filter(item -> StringUtils.equals(item.getType(), TestPlanConstants.TEST_PLAN_TYPE_GROUP)).map(TestPlanResponse::getId).toList();
|
List<String> groupIds = testPlanResponses.stream().filter(item -> StringUtils.equals(item.getType(), TestPlanConstants.TEST_PLAN_TYPE_GROUP)).map(TestPlanResponse::getId).toList();
|
||||||
|
|
|
@ -1,57 +1,33 @@
|
||||||
package io.metersphere.plan.service;
|
package io.metersphere.plan.service;
|
||||||
|
|
||||||
import io.metersphere.plan.domain.TestPlan;
|
import io.metersphere.plan.domain.TestPlan;
|
||||||
import io.metersphere.plan.dto.AssociationNode;
|
|
||||||
import io.metersphere.plan.dto.AssociationNodeSortDTO;
|
|
||||||
import io.metersphere.plan.dto.ResourceLogInsertModule;
|
import io.metersphere.plan.dto.ResourceLogInsertModule;
|
||||||
import io.metersphere.plan.dto.TestPlanResourceAssociationParam;
|
import io.metersphere.plan.dto.TestPlanResourceAssociationParam;
|
||||||
import io.metersphere.plan.dto.request.BasePlanCaseBatchRequest;
|
import io.metersphere.plan.dto.request.BasePlanCaseBatchRequest;
|
||||||
import io.metersphere.plan.dto.response.TestPlanAssociationResponse;
|
import io.metersphere.plan.dto.response.TestPlanAssociationResponse;
|
||||||
import io.metersphere.plan.mapper.TestPlanMapper;
|
import io.metersphere.plan.mapper.TestPlanMapper;
|
||||||
import io.metersphere.project.dto.ModuleSortCountResultDTO;
|
|
||||||
import io.metersphere.project.dto.NodeSortQueryParam;
|
|
||||||
import io.metersphere.project.service.MoveNodeService;
|
|
||||||
import io.metersphere.project.utils.NodeSortUtils;
|
|
||||||
import io.metersphere.sdk.exception.MSException;
|
|
||||||
import io.metersphere.sdk.util.Translator;
|
|
||||||
import io.metersphere.system.dto.LogInsertModule;
|
import io.metersphere.system.dto.LogInsertModule;
|
||||||
import io.metersphere.system.dto.sdk.request.NodeMoveRequest;
|
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
//测试计划关联表 通用方法
|
//测试计划关联表 通用方法
|
||||||
@Service
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public abstract class TestPlanResourceService extends MoveNodeService {
|
public abstract class TestPlanResourceService extends TestPlanSortService {
|
||||||
|
|
||||||
@Resource
|
|
||||||
private TestPlanMapper testPlanMapper;
|
|
||||||
@Resource
|
|
||||||
private TestPlanResourceLogService testPlanResourceLogService;
|
|
||||||
|
|
||||||
protected static final long DEFAULT_NODE_INTERVAL_POS = NodeSortUtils.DEFAULT_NODE_INTERVAL_POS;
|
|
||||||
|
|
||||||
public abstract void updatePos(String id, long pos);
|
|
||||||
|
|
||||||
public abstract void refreshPos(String testPlanId);
|
|
||||||
|
|
||||||
public abstract void deleteBatchByTestPlanId(List<String> testPlanIdList);
|
public abstract void deleteBatchByTestPlanId(List<String> testPlanIdList);
|
||||||
|
|
||||||
public abstract Map<String, Long> caseExecResultCount(String testPlanId);
|
public abstract Map<String, Long> caseExecResultCount(String testPlanId);
|
||||||
|
|
||||||
private static final String MOVE_POS_OPERATOR_LESS = "lessThan";
|
@Resource
|
||||||
private static final String MOVE_POS_OPERATOR_MORE = "moreThan";
|
private TestPlanMapper testPlanMapper;
|
||||||
private static final String DRAG_NODE_NOT_EXIST = "drag_node.not.exist";
|
@Resource
|
||||||
|
private TestPlanResourceLogService testPlanResourceLogService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 取消关联资源od
|
* 取消关联资源od
|
||||||
|
@ -75,73 +51,4 @@ public abstract class TestPlanResourceService extends MoveNodeService {
|
||||||
}
|
}
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建节点排序的参数
|
|
||||||
*
|
|
||||||
* @param request 拖拽的前端请求参数
|
|
||||||
* @param selectIdNodeFunc 通过id查询节点的函数
|
|
||||||
* @param selectPosNodeFunc 通过parentId和pos运算符查询节点的函数
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public AssociationNodeSortDTO getNodeSortDTO(NodeMoveRequest request, String testPlanId, Function<String, AssociationNode> selectIdNodeFunc, Function<NodeSortQueryParam, AssociationNode> selectPosNodeFunc) {
|
|
||||||
if (StringUtils.equals(request.getDragNodeId(), request.getDropNodeId())) {
|
|
||||||
//两种节点不能一样
|
|
||||||
throw new MSException(Translator.get("invalid_parameter") + ": drag node and drop node");
|
|
||||||
}
|
|
||||||
|
|
||||||
AssociationNode dragNode = selectIdNodeFunc.apply(request.getDragNodeId());
|
|
||||||
if (dragNode == null) {
|
|
||||||
throw new MSException(Translator.get(DRAG_NODE_NOT_EXIST) + ":" + request.getDragNodeId());
|
|
||||||
}
|
|
||||||
|
|
||||||
AssociationNode dropNode = selectIdNodeFunc.apply(request.getDropNodeId());
|
|
||||||
if (dropNode == null) {
|
|
||||||
throw new MSException(Translator.get(DRAG_NODE_NOT_EXIST) + ":" + request.getDropNodeId());
|
|
||||||
}
|
|
||||||
|
|
||||||
AssociationNode previousNode;
|
|
||||||
AssociationNode nextNode;
|
|
||||||
|
|
||||||
if (request.getDropPosition() == 1) {
|
|
||||||
//dropPosition=1: 放到dropNode节点后,原dropNode后面的节点之前
|
|
||||||
previousNode = dropNode;
|
|
||||||
|
|
||||||
NodeSortQueryParam sortParam = new NodeSortQueryParam();
|
|
||||||
sortParam.setParentId(testPlanId);
|
|
||||||
sortParam.setPos(previousNode.getPos());
|
|
||||||
sortParam.setOperator(MOVE_POS_OPERATOR_MORE);
|
|
||||||
nextNode = selectPosNodeFunc.apply(sortParam);
|
|
||||||
} else if (request.getDropPosition() == -1) {
|
|
||||||
//dropPosition=-1: 放到dropNode节点前,原dropNode前面的节点之后
|
|
||||||
nextNode = dropNode;
|
|
||||||
NodeSortQueryParam sortParam = new NodeSortQueryParam();
|
|
||||||
sortParam.setPos(nextNode.getPos());
|
|
||||||
sortParam.setParentId(testPlanId);
|
|
||||||
sortParam.setOperator(MOVE_POS_OPERATOR_LESS);
|
|
||||||
previousNode = selectPosNodeFunc.apply(sortParam);
|
|
||||||
} else {
|
|
||||||
throw new MSException(Translator.get("invalid_parameter") + ": dropPosition");
|
|
||||||
}
|
|
||||||
|
|
||||||
return new AssociationNodeSortDTO(testPlanId, dragNode, previousNode, nextNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
//排序
|
|
||||||
public void sort(AssociationNodeSortDTO sortDTO) {
|
|
||||||
|
|
||||||
// 获取相邻节点
|
|
||||||
AssociationNode previousNode = sortDTO.getPreviousNode();
|
|
||||||
AssociationNode nextNode = sortDTO.getNextNode();
|
|
||||||
|
|
||||||
ModuleSortCountResultDTO countResultDTO = NodeSortUtils.countModuleSort(
|
|
||||||
previousNode == null ? -1 : previousNode.getPos(),
|
|
||||||
nextNode == null ? -1 : nextNode.getPos());
|
|
||||||
|
|
||||||
updatePos(sortDTO.getSortNode().getId(), countResultDTO.getPos());
|
|
||||||
if (countResultDTO.isRefreshPos()) {
|
|
||||||
refreshPos(sortDTO.getTestPlanId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package io.metersphere.plan.service;
|
||||||
import io.metersphere.plan.domain.*;
|
import io.metersphere.plan.domain.*;
|
||||||
import io.metersphere.plan.dto.request.*;
|
import io.metersphere.plan.dto.request.*;
|
||||||
import io.metersphere.plan.dto.response.TestPlanDetailResponse;
|
import io.metersphere.plan.dto.response.TestPlanDetailResponse;
|
||||||
|
import io.metersphere.plan.dto.response.TestPlanResourceSortResponse;
|
||||||
import io.metersphere.plan.mapper.*;
|
import io.metersphere.plan.mapper.*;
|
||||||
import io.metersphere.sdk.constants.*;
|
import io.metersphere.sdk.constants.*;
|
||||||
import io.metersphere.sdk.exception.MSException;
|
import io.metersphere.sdk.exception.MSException;
|
||||||
|
@ -13,6 +14,8 @@ import io.metersphere.sdk.util.Translator;
|
||||||
import io.metersphere.system.domain.ScheduleExample;
|
import io.metersphere.system.domain.ScheduleExample;
|
||||||
import io.metersphere.system.domain.TestPlanModuleExample;
|
import io.metersphere.system.domain.TestPlanModuleExample;
|
||||||
import io.metersphere.system.domain.User;
|
import io.metersphere.system.domain.User;
|
||||||
|
import io.metersphere.system.dto.LogInsertModule;
|
||||||
|
import io.metersphere.system.dto.sdk.request.PosRequest;
|
||||||
import io.metersphere.system.log.constants.OperationLogType;
|
import io.metersphere.system.log.constants.OperationLogType;
|
||||||
import io.metersphere.system.mapper.ScheduleMapper;
|
import io.metersphere.system.mapper.ScheduleMapper;
|
||||||
import io.metersphere.system.mapper.TestPlanModuleMapper;
|
import io.metersphere.system.mapper.TestPlanModuleMapper;
|
||||||
|
@ -49,6 +52,8 @@ public class TestPlanService extends TestPlanBaseUtilsService {
|
||||||
@Resource
|
@Resource
|
||||||
private ExtTestPlanMapper extTestPlanMapper;
|
private ExtTestPlanMapper extTestPlanMapper;
|
||||||
@Resource
|
@Resource
|
||||||
|
private TestPlanGroupService testPlanGroupService;
|
||||||
|
@Resource
|
||||||
private TestPlanConfigMapper testPlanConfigMapper;
|
private TestPlanConfigMapper testPlanConfigMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private TestPlanLogService testPlanLogService;
|
private TestPlanLogService testPlanLogService;
|
||||||
|
@ -82,12 +87,6 @@ public class TestPlanService extends TestPlanBaseUtilsService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建测试计划
|
* 创建测试计划
|
||||||
*
|
|
||||||
* @param testPlanCreateRequest
|
|
||||||
* @param operator
|
|
||||||
* @param requestUrl
|
|
||||||
* @param requestMethod
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
public TestPlan add(TestPlanCreateRequest testPlanCreateRequest, String operator, String requestUrl, String requestMethod) {
|
public TestPlan add(TestPlanCreateRequest testPlanCreateRequest, String operator, String requestUrl, String requestMethod) {
|
||||||
TestPlan testPlan = savePlanDTO(testPlanCreateRequest, operator, null);
|
TestPlan testPlan = savePlanDTO(testPlanCreateRequest, operator, null);
|
||||||
|
@ -108,8 +107,7 @@ public class TestPlanService extends TestPlanBaseUtilsService {
|
||||||
checkModule(createOrCopyRequest.getModuleId());
|
checkModule(createOrCopyRequest.getModuleId());
|
||||||
TestPlan createTestPlan = new TestPlan();
|
TestPlan createTestPlan = new TestPlan();
|
||||||
BeanUtils.copyBean(createTestPlan, createOrCopyRequest);
|
BeanUtils.copyBean(createTestPlan, createOrCopyRequest);
|
||||||
// 5.21,查询需求文档、测试用例:测试计划名称允许重复
|
initTestPlanPos(createTestPlan);
|
||||||
// validateTestPlan(createTestPlan);
|
|
||||||
|
|
||||||
createTestPlan.setId(IDGenerator.nextStr());
|
createTestPlan.setId(IDGenerator.nextStr());
|
||||||
long operateTime = System.currentTimeMillis();
|
long operateTime = System.currentTimeMillis();
|
||||||
|
@ -138,6 +136,22 @@ public class TestPlanService extends TestPlanBaseUtilsService {
|
||||||
return createTestPlan;
|
return createTestPlan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//校验测试计划
|
||||||
|
private void initTestPlanPos(TestPlan createTestPlan) {
|
||||||
|
if (!StringUtils.equals(createTestPlan.getGroupId(), TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID)) {
|
||||||
|
//如果测试计划组不为NONE,判断是否真实存在并未归档
|
||||||
|
TestPlanExample example = new TestPlanExample();
|
||||||
|
example.createCriteria().andIdEqualTo(createTestPlan.getGroupId()).andStatusNotEqualTo(TEST_PLAN_STATUS_ARCHIVED);
|
||||||
|
if (testPlanMapper.countByExample(example) == 0) {
|
||||||
|
throw new MSException(Translator.get("test_plan.group.error"));
|
||||||
|
} else {
|
||||||
|
createTestPlan.setPos(testPlanGroupService.getNextOrder(createTestPlan.getGroupId()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
createTestPlan.setPos(0L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除测试计划
|
* 删除测试计划
|
||||||
|
@ -179,6 +193,7 @@ public class TestPlanService extends TestPlanBaseUtilsService {
|
||||||
private void deleteGroupByList(List<String> testPlanGroupIds) {
|
private void deleteGroupByList(List<String> testPlanGroupIds) {
|
||||||
if (CollectionUtils.isNotEmpty(testPlanGroupIds)) {
|
if (CollectionUtils.isNotEmpty(testPlanGroupIds)) {
|
||||||
TestPlanReportService testPlanReportService = CommonBeanFactory.getBean(TestPlanReportService.class);
|
TestPlanReportService testPlanReportService = CommonBeanFactory.getBean(TestPlanReportService.class);
|
||||||
|
assert testPlanReportService != null;
|
||||||
BatchProcessUtils.consumerByString(testPlanGroupIds, (deleteGroupIds) -> {
|
BatchProcessUtils.consumerByString(testPlanGroupIds, (deleteGroupIds) -> {
|
||||||
/*
|
/*
|
||||||
* 计划组删除逻辑{第一版需求: 删除组, 组下的子计划Group置为None}:
|
* 计划组删除逻辑{第一版需求: 删除组, 组下的子计划Group置为None}:
|
||||||
|
@ -189,12 +204,13 @@ public class TestPlanService extends TestPlanBaseUtilsService {
|
||||||
testPlanExample.createCriteria().andGroupIdIn(deleteGroupIds);
|
testPlanExample.createCriteria().andGroupIdIn(deleteGroupIds);
|
||||||
List<TestPlan> deleteGroupPlans = testPlanMapper.selectByExample(testPlanExample);
|
List<TestPlan> deleteGroupPlans = testPlanMapper.selectByExample(testPlanExample);
|
||||||
List<String> deleteGroupPlanIds = deleteGroupPlans.stream().map(TestPlan::getId).toList();
|
List<String> deleteGroupPlanIds = deleteGroupPlans.stream().map(TestPlan::getId).toList();
|
||||||
if (CollectionUtils.isNotEmpty(deleteGroupPlanIds)) {
|
List<String> allDeleteIds = ListUtils.union(deleteGroupIds, deleteGroupPlanIds);
|
||||||
// 级联删除子计划关联的资源(计划组不存在关联的资源)
|
if (CollectionUtils.isNotEmpty(allDeleteIds)) {
|
||||||
|
// 级联删除子计划关联的资源(计划组不存在关联的资源,但是存在报告)
|
||||||
this.cascadeDeleteTestPlanIds(deleteGroupPlanIds, testPlanReportService);
|
this.cascadeDeleteTestPlanIds(deleteGroupPlanIds, testPlanReportService);
|
||||||
}
|
}
|
||||||
testPlanExample.clear();
|
testPlanExample.clear();
|
||||||
testPlanExample.createCriteria().andIdIn(ListUtils.union(deleteGroupIds, deleteGroupPlanIds));
|
testPlanExample.createCriteria().andIdIn(allDeleteIds);
|
||||||
testPlanMapper.deleteByExample(testPlanExample);
|
testPlanMapper.deleteByExample(testPlanExample);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -275,12 +291,6 @@ public class TestPlanService extends TestPlanBaseUtilsService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新测试计划
|
* 更新测试计划
|
||||||
*
|
|
||||||
* @param request
|
|
||||||
* @param userId
|
|
||||||
* @param requestUrl
|
|
||||||
* @param requestMethod
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
public TestPlan update(TestPlanUpdateRequest request, String userId, String requestUrl, String requestMethod) {
|
public TestPlan update(TestPlanUpdateRequest request, String userId, String requestUrl, String requestMethod) {
|
||||||
this.checkTestPlanNotArchived(request.getId());
|
this.checkTestPlanNotArchived(request.getId());
|
||||||
|
@ -296,8 +306,6 @@ public class TestPlanService extends TestPlanBaseUtilsService {
|
||||||
if (StringUtils.isNotBlank(request.getName())) {
|
if (StringUtils.isNotBlank(request.getName())) {
|
||||||
updateTestPlan.setName(request.getName());
|
updateTestPlan.setName(request.getName());
|
||||||
updateTestPlan.setProjectId(testPlan.getProjectId());
|
updateTestPlan.setProjectId(testPlan.getProjectId());
|
||||||
// 5.21,查询需求文档、测试用例:测试计划名称允许重复
|
|
||||||
// validateTestPlan(updateTestPlan);
|
|
||||||
}
|
}
|
||||||
if (CollectionUtils.isNotEmpty(request.getTags())) {
|
if (CollectionUtils.isNotEmpty(request.getTags())) {
|
||||||
updateTestPlan.setTags(new ArrayList<>(request.getTags()));
|
updateTestPlan.setTags(new ArrayList<>(request.getTags()));
|
||||||
|
@ -706,4 +714,11 @@ public class TestPlanService extends TestPlanBaseUtilsService {
|
||||||
testPlan.setStatus(testPlanFinalStatus);
|
testPlan.setStatus(testPlanFinalStatus);
|
||||||
testPlanMapper.updateByPrimaryKeySelective(testPlan);
|
testPlanMapper.updateByPrimaryKeySelective(testPlan);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TestPlanResourceSortResponse sortInGroup(PosRequest request, LogInsertModule logInsertModule) {
|
||||||
|
testPlanGroupService.sort(request);
|
||||||
|
testPlanLogService.saveMoveLog(testPlanMapper.selectByPrimaryKey(request.getMoveId()), request.getMoveId(), logInsertModule);
|
||||||
|
return new TestPlanResourceSortResponse(1);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
package io.metersphere.plan.service;
|
||||||
|
|
||||||
|
import io.metersphere.project.service.MoveNodeService;
|
||||||
|
import io.metersphere.project.utils.NodeSortUtils;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
//测试计划关联表 通用方法
|
||||||
|
@Service
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public abstract class TestPlanSortService extends MoveNodeService {
|
||||||
|
|
||||||
|
protected static final long DEFAULT_NODE_INTERVAL_POS = NodeSortUtils.DEFAULT_NODE_INTERVAL_POS;
|
||||||
|
|
||||||
|
public abstract void updatePos(String id, long pos);
|
||||||
|
|
||||||
|
public abstract void refreshPos(String testPlanId);
|
||||||
|
|
||||||
|
private static final String MOVE_POS_OPERATOR_LESS = "lessThan";
|
||||||
|
private static final String MOVE_POS_OPERATOR_MORE = "moreThan";
|
||||||
|
private static final String DRAG_NODE_NOT_EXIST = "drag_node.not.exist";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建节点排序的参数
|
||||||
|
*
|
||||||
|
* @param request 拖拽的前端请求参数
|
||||||
|
* @param selectIdNodeFunc 通过id查询节点的函数
|
||||||
|
* @param selectPosNodeFunc 通过parentId和pos运算符查询节点的函数
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// public MoveNodeSortDTO getNodeSortDTO(NodeMoveRequest request, String testPlanId, Function<String, DropNode> selectIdNodeFunc, Function<NodeSortQueryParam, DropNode> selectPosNodeFunc) {
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// if (StringUtils.equals(request.getDragNodeId(), request.getDropNodeId())) {
|
||||||
|
// //两种节点不能一样
|
||||||
|
// throw new MSException(Translator.get("invalid_parameter") + ": drag node and drop node");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// DropNode dragNode = selectIdNodeFunc.apply(request.getDragNodeId());
|
||||||
|
// if (dragNode == null) {
|
||||||
|
// throw new MSException(Translator.get(DRAG_NODE_NOT_EXIST) + ":" + request.getDragNodeId());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// DropNode dropNode = selectIdNodeFunc.apply(request.getDropNodeId());
|
||||||
|
// if (dropNode == null) {
|
||||||
|
// throw new MSException(Translator.get(DRAG_NODE_NOT_EXIST) + ":" + request.getDropNodeId());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// DropNode previousNode;
|
||||||
|
// DropNode nextNode;
|
||||||
|
//
|
||||||
|
// if (request.getDropPosition() == 1) {
|
||||||
|
// //dropPosition=1: 放到dropNode节点后,原dropNode后面的节点之前
|
||||||
|
// previousNode = dropNode;
|
||||||
|
//
|
||||||
|
// NodeSortQueryParam sortParam = new NodeSortQueryParam();
|
||||||
|
// sortParam.setParentId(testPlanId);
|
||||||
|
// sortParam.setPos(previousNode.getPos());
|
||||||
|
// sortParam.setOperator(MOVE_POS_OPERATOR_MORE);
|
||||||
|
// nextNode = selectPosNodeFunc.apply(sortParam);
|
||||||
|
// } else if (request.getDropPosition() == -1) {
|
||||||
|
// //dropPosition=-1: 放到dropNode节点前,原dropNode前面的节点之后
|
||||||
|
// nextNode = dropNode;
|
||||||
|
// NodeSortQueryParam sortParam = new NodeSortQueryParam();
|
||||||
|
// sortParam.setPos(nextNode.getPos());
|
||||||
|
// sortParam.setParentId(testPlanId);
|
||||||
|
// sortParam.setOperator(MOVE_POS_OPERATOR_LESS);
|
||||||
|
// previousNode = selectPosNodeFunc.apply(sortParam);
|
||||||
|
// } else {
|
||||||
|
// throw new MSException(Translator.get("invalid_parameter") + ": dropPosition");
|
||||||
|
// }
|
||||||
|
// return new MoveNodeSortDTO(testPlanId, dragNode, previousNode, nextNode);
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ import io.metersphere.project.domain.Project;
|
||||||
import io.metersphere.project.dto.filemanagement.request.FileModuleCreateRequest;
|
import io.metersphere.project.dto.filemanagement.request.FileModuleCreateRequest;
|
||||||
import io.metersphere.project.dto.filemanagement.request.FileModuleUpdateRequest;
|
import io.metersphere.project.dto.filemanagement.request.FileModuleUpdateRequest;
|
||||||
import io.metersphere.sdk.constants.*;
|
import io.metersphere.sdk.constants.*;
|
||||||
|
import io.metersphere.sdk.util.BeanUtils;
|
||||||
import io.metersphere.sdk.util.CommonBeanFactory;
|
import io.metersphere.sdk.util.CommonBeanFactory;
|
||||||
import io.metersphere.sdk.util.JSON;
|
import io.metersphere.sdk.util.JSON;
|
||||||
import io.metersphere.system.base.BaseTest;
|
import io.metersphere.system.base.BaseTest;
|
||||||
|
@ -26,6 +27,7 @@ import io.metersphere.system.dto.AddProjectRequest;
|
||||||
import io.metersphere.system.dto.sdk.BaseTreeNode;
|
import io.metersphere.system.dto.sdk.BaseTreeNode;
|
||||||
import io.metersphere.system.dto.sdk.enums.MoveTypeEnum;
|
import io.metersphere.system.dto.sdk.enums.MoveTypeEnum;
|
||||||
import io.metersphere.system.dto.sdk.request.NodeMoveRequest;
|
import io.metersphere.system.dto.sdk.request.NodeMoveRequest;
|
||||||
|
import io.metersphere.system.dto.sdk.request.PosRequest;
|
||||||
import io.metersphere.system.log.constants.OperationLogModule;
|
import io.metersphere.system.log.constants.OperationLogModule;
|
||||||
import io.metersphere.system.log.constants.OperationLogType;
|
import io.metersphere.system.log.constants.OperationLogType;
|
||||||
import io.metersphere.system.mapper.TestPlanModuleMapper;
|
import io.metersphere.system.mapper.TestPlanModuleMapper;
|
||||||
|
@ -106,6 +108,7 @@ public class TestPlanTests extends BaseTest {
|
||||||
private static final String URL_POST_TEST_PLAN_STATISTICS = "/test-plan/statistics";
|
private static final String URL_POST_TEST_PLAN_STATISTICS = "/test-plan/statistics";
|
||||||
private static final String URL_POST_TEST_PLAN_MODULE_COUNT = "/test-plan/module/count";
|
private static final String URL_POST_TEST_PLAN_MODULE_COUNT = "/test-plan/module/count";
|
||||||
private static final String URL_POST_TEST_PLAN_ADD = "/test-plan/add";
|
private static final String URL_POST_TEST_PLAN_ADD = "/test-plan/add";
|
||||||
|
private static final String URL_POST_TEST_PLAN_SORT = "/test-plan/sort";
|
||||||
private static final String URL_POST_TEST_PLAN_UPDATE = "/test-plan/update";
|
private static final String URL_POST_TEST_PLAN_UPDATE = "/test-plan/update";
|
||||||
private static final String URL_POST_TEST_PLAN_BATCH_DELETE = "/test-plan/batch-delete";
|
private static final String URL_POST_TEST_PLAN_BATCH_DELETE = "/test-plan/batch-delete";
|
||||||
|
|
||||||
|
@ -136,7 +139,7 @@ public class TestPlanTests extends BaseTest {
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void initTestData() {
|
public void initTestData() {
|
||||||
//文件管理专用项目
|
//测试计划专用项目
|
||||||
if (project == null) {
|
if (project == null) {
|
||||||
AddProjectRequest initProject = new AddProjectRequest();
|
AddProjectRequest initProject = new AddProjectRequest();
|
||||||
initProject.setOrganizationId("100001");
|
initProject.setOrganizationId("100001");
|
||||||
|
@ -607,7 +610,6 @@ public class TestPlanTests extends BaseTest {
|
||||||
request.setType(TestPlanConstants.TEST_PLAN_TYPE_PLAN);
|
request.setType(TestPlanConstants.TEST_PLAN_TYPE_PLAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
抽查:
|
抽查:
|
||||||
testPlan_13没有设置计划开始时间、没有设置重复添加用例和自动更新状态、阈值为100、描述为空;
|
testPlan_13没有设置计划开始时间、没有设置重复添加用例和自动更新状态、阈值为100、描述为空;
|
||||||
|
@ -681,25 +683,133 @@ public class TestPlanTests extends BaseTest {
|
||||||
request.setPassThreshold(100);
|
request.setPassThreshold(100);
|
||||||
this.requestPostPermissionTest(PermissionConstants.TEST_PLAN_READ_ADD, URL_POST_TEST_PLAN_ADD, request);
|
this.requestPostPermissionTest(PermissionConstants.TEST_PLAN_READ_ADD, URL_POST_TEST_PLAN_ADD, request);
|
||||||
|
|
||||||
|
|
||||||
|
this.checkTestPlanSortInGroup(groupTestPlanId7);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void checkTestPlanSortInGroup(String groupTestPlanId7) throws Exception {
|
||||||
|
/*
|
||||||
|
排序校验用例设计:
|
||||||
|
1.第一个移动到最后一个。
|
||||||
|
2.最后一个移动到第一个(还原为原来的顺序)
|
||||||
|
3.第三个移动到第二个
|
||||||
|
4.修改第一个和第二个之间的pos差小于2,将第三个移动到第二个(还原为原来的顺序),并检查pos有没有初始化
|
||||||
|
*/
|
||||||
|
|
||||||
|
TestPlanExample example = new TestPlanExample();
|
||||||
|
example.createCriteria().andGroupIdEqualTo(groupTestPlanId7);
|
||||||
|
example.setOrderByClause("pos asc");
|
||||||
|
List<TestPlan> defaultTestPlanInGroup = testPlanMapper.selectByExample(example);
|
||||||
|
List<TestPlan> lastTestPlanInGroup = defaultTestPlanInGroup;
|
||||||
|
TestPlan movePlan, targetPlan = null;
|
||||||
|
PosRequest posRequest = null;
|
||||||
|
TestPlanResourceSortResponse response = null;
|
||||||
|
|
||||||
|
// 第一个移动到最后一个
|
||||||
|
movePlan = lastTestPlanInGroup.getFirst();
|
||||||
|
targetPlan = lastTestPlanInGroup.getLast();
|
||||||
|
posRequest = new PosRequest(project.getId(), movePlan.getId(), targetPlan.getId(), MoveTypeEnum.AFTER.name());
|
||||||
|
response = JSON.parseObject(
|
||||||
|
JSON.toJSONString(
|
||||||
|
JSON.parseObject(
|
||||||
|
this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_SORT, posRequest)
|
||||||
|
.getResponse().getContentAsString(), ResultHolder.class).getData()),
|
||||||
|
TestPlanResourceSortResponse.class);
|
||||||
|
//位置校验
|
||||||
|
List<TestPlan> newTestPlanInGroup = testPlanMapper.selectByExample(example);
|
||||||
|
Assertions.assertEquals(response.getSortNodeNum(), 1);
|
||||||
|
Assertions.assertEquals(newTestPlanInGroup.size(), lastTestPlanInGroup.size());
|
||||||
|
for (int newListIndex = 0; newListIndex < newTestPlanInGroup.size(); newListIndex++) {
|
||||||
|
int oldListIndex = newListIndex == newTestPlanInGroup.size() - 1 ? 0 : newListIndex + 1;
|
||||||
|
Assertions.assertEquals(newTestPlanInGroup.get(newListIndex).getId(), lastTestPlanInGroup.get(oldListIndex).getId());
|
||||||
|
}
|
||||||
|
lastTestPlanInGroup = newTestPlanInGroup;
|
||||||
|
|
||||||
|
// 最后一个移动到第一个 (还原为原来的顺序)
|
||||||
|
movePlan = lastTestPlanInGroup.getLast();
|
||||||
|
targetPlan = lastTestPlanInGroup.getFirst();
|
||||||
|
posRequest = new PosRequest(project.getId(), movePlan.getId(), targetPlan.getId(), MoveTypeEnum.BEFORE.name());
|
||||||
|
response = JSON.parseObject(
|
||||||
|
JSON.toJSONString(
|
||||||
|
JSON.parseObject(
|
||||||
|
this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_SORT, posRequest)
|
||||||
|
.getResponse().getContentAsString(), ResultHolder.class).getData()),
|
||||||
|
TestPlanResourceSortResponse.class);
|
||||||
|
//位置校验
|
||||||
|
newTestPlanInGroup = testPlanMapper.selectByExample(example);
|
||||||
|
Assertions.assertEquals(response.getSortNodeNum(), 1);
|
||||||
|
Assertions.assertEquals(newTestPlanInGroup.size(), lastTestPlanInGroup.size());
|
||||||
|
for (int newListIndex = 0; newListIndex < newTestPlanInGroup.size(); newListIndex++) {
|
||||||
|
Assertions.assertEquals(newTestPlanInGroup.get(newListIndex).getId(), defaultTestPlanInGroup.get(newListIndex).getId());
|
||||||
|
}
|
||||||
|
lastTestPlanInGroup = newTestPlanInGroup;
|
||||||
|
|
||||||
|
// 第三个移动到第二个
|
||||||
|
movePlan = lastTestPlanInGroup.get(2);
|
||||||
|
targetPlan = lastTestPlanInGroup.get(1);
|
||||||
|
posRequest = new PosRequest(project.getId(), movePlan.getId(), targetPlan.getId(), MoveTypeEnum.BEFORE.name());
|
||||||
|
response = JSON.parseObject(
|
||||||
|
JSON.toJSONString(
|
||||||
|
JSON.parseObject(
|
||||||
|
this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_SORT, posRequest)
|
||||||
|
.getResponse().getContentAsString(), ResultHolder.class).getData()),
|
||||||
|
TestPlanResourceSortResponse.class);
|
||||||
|
//位置校验
|
||||||
|
newTestPlanInGroup = testPlanMapper.selectByExample(example);
|
||||||
|
Assertions.assertEquals(response.getSortNodeNum(), 1);
|
||||||
|
Assertions.assertEquals(newTestPlanInGroup.size(), lastTestPlanInGroup.size());
|
||||||
|
for (int newListIndex = 0; newListIndex < newTestPlanInGroup.size(); newListIndex++) {
|
||||||
|
int oldListIndex = newListIndex;
|
||||||
|
if (oldListIndex == 1) {
|
||||||
|
oldListIndex = 2;
|
||||||
|
} else if (oldListIndex == 2) {
|
||||||
|
oldListIndex = 1;
|
||||||
|
}
|
||||||
|
Assertions.assertEquals(newTestPlanInGroup.get(newListIndex).getId(), lastTestPlanInGroup.get(oldListIndex).getId());
|
||||||
|
}
|
||||||
|
lastTestPlanInGroup = newTestPlanInGroup;
|
||||||
|
|
||||||
|
// 修改第一个和第二个之间的pos差为2(拖拽的最小pos差),将第三个移动到第二个(换回来),然后检查pos有没有变化
|
||||||
|
movePlan = lastTestPlanInGroup.get(2);
|
||||||
|
targetPlan = lastTestPlanInGroup.get(1);
|
||||||
|
targetPlan.setPos(lastTestPlanInGroup.get(0).getPos() + 2);
|
||||||
|
testPlanMapper.updateByPrimaryKey(targetPlan);
|
||||||
|
|
||||||
|
posRequest = new PosRequest(project.getId(), movePlan.getId(), targetPlan.getId(), MoveTypeEnum.BEFORE.name());
|
||||||
|
response = JSON.parseObject(
|
||||||
|
JSON.toJSONString(
|
||||||
|
JSON.parseObject(
|
||||||
|
this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_SORT, posRequest)
|
||||||
|
.getResponse().getContentAsString(), ResultHolder.class).getData()),
|
||||||
|
TestPlanResourceSortResponse.class);
|
||||||
|
//位置校验
|
||||||
|
newTestPlanInGroup = testPlanMapper.selectByExample(example);
|
||||||
|
Assertions.assertEquals(response.getSortNodeNum(), 1);
|
||||||
|
Assertions.assertEquals(newTestPlanInGroup.size(), lastTestPlanInGroup.size());
|
||||||
|
long lastPos = 0;
|
||||||
|
for (int newListIndex = 0; newListIndex < newTestPlanInGroup.size(); newListIndex++) {
|
||||||
|
Assertions.assertEquals(newTestPlanInGroup.get(newListIndex).getId(), defaultTestPlanInGroup.get(newListIndex).getId());
|
||||||
|
Assertions.assertTrue(newTestPlanInGroup.get(newListIndex).getPos() > (lastPos + 1));
|
||||||
|
lastPos = newTestPlanInGroup.get(newListIndex).getPos();
|
||||||
|
}
|
||||||
|
}
|
||||||
@Test
|
@Test
|
||||||
@Order(12)
|
@Order(12)
|
||||||
public void testPlanPageCountTest() throws Exception {
|
public void testPlanPageCountTest() throws Exception {
|
||||||
TestPlanTableRequest testPlanTableRequest = new TestPlanTableRequest();
|
TestPlanTableRequest dataRequest = new TestPlanTableRequest();
|
||||||
testPlanTableRequest.setProjectId(project.getId());
|
dataRequest.setProjectId(project.getId());
|
||||||
testPlanTableRequest.setType("ALL");
|
dataRequest.setType("ALL");
|
||||||
testPlanTableRequest.setPageSize(10);
|
dataRequest.setPageSize(10);
|
||||||
testPlanTableRequest.setCurrent(1);
|
dataRequest.setCurrent(1);
|
||||||
|
|
||||||
//测试项目没有开启测试计划模块时能否使用
|
//测试项目没有开启测试计划模块时能否使用
|
||||||
testPlanTestService.removeProjectModule(project, PROJECT_MODULE, "testPlan");
|
testPlanTestService.removeProjectModule(project, PROJECT_MODULE, "testPlan");
|
||||||
this.requestPost(URL_POST_TEST_PLAN_MODULE_COUNT, testPlanTableRequest).andExpect(status().is5xxServerError());
|
this.requestPost(URL_POST_TEST_PLAN_MODULE_COUNT, dataRequest).andExpect(status().is5xxServerError());
|
||||||
this.requestPost(URL_POST_TEST_PLAN_MODULE_COUNT, testPlanTableRequest).andExpect(status().is5xxServerError());
|
this.requestPost(URL_POST_TEST_PLAN_MODULE_COUNT, dataRequest).andExpect(status().is5xxServerError());
|
||||||
//恢复
|
//恢复
|
||||||
testPlanTestService.resetProjectModule(project, PROJECT_MODULE);
|
testPlanTestService.resetProjectModule(project, PROJECT_MODULE);
|
||||||
|
|
||||||
MvcResult moduleCountResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_MODULE_COUNT, testPlanTableRequest);
|
MvcResult moduleCountResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_MODULE_COUNT, dataRequest);
|
||||||
String moduleCountReturnData = moduleCountResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
String moduleCountReturnData = moduleCountResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||||
Map<String, Object> moduleCountMap = JSON.parseObject(JSON.toJSONString(JSON.parseObject(moduleCountReturnData, ResultHolder.class).getData()), Map.class);
|
Map<String, Object> moduleCountMap = JSON.parseObject(JSON.toJSONString(JSON.parseObject(moduleCountReturnData, ResultHolder.class).getData()), Map.class);
|
||||||
AtomicBoolean testPlanIsEmpty = new AtomicBoolean(true);
|
AtomicBoolean testPlanIsEmpty = new AtomicBoolean(true);
|
||||||
|
@ -711,11 +821,19 @@ public class TestPlanTests extends BaseTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (testPlanIsEmpty.get()) {
|
if (testPlanIsEmpty.get()) {
|
||||||
//如果没有数据,先创建999条再调用这个方法
|
//如果没有数据,先创建再调用这个方法
|
||||||
this.testPlanAddTest();
|
this.testPlanAddTest();
|
||||||
this.testPlanPageCountTest();
|
this.testPlanPageCountTest();
|
||||||
} else {
|
} else {
|
||||||
//this.checkModuleCount(moduleCountMap, a1NodeCount, a2NodeCount, a3NodeCount, a1a1NodeCount, a1b1NodeCount);
|
//只查询组
|
||||||
|
TestPlanTableRequest groupRequest = new TestPlanTableRequest();
|
||||||
|
//查询游离态测试计划
|
||||||
|
TestPlanTableRequest onlyPlanRequest = new TestPlanTableRequest();
|
||||||
|
BeanUtils.copyBean(groupRequest, dataRequest);
|
||||||
|
BeanUtils.copyBean(onlyPlanRequest, dataRequest);
|
||||||
|
groupRequest.setType(TestPlanConstants.TEST_PLAN_TYPE_GROUP);
|
||||||
|
onlyPlanRequest.setType(TestPlanConstants.TEST_PLAN_TYPE_PLAN);
|
||||||
|
|
||||||
|
|
||||||
BaseTreeNode a1Node = TestPlanTestUtils.getNodeByName(preliminaryTreeNodes, "a1");
|
BaseTreeNode a1Node = TestPlanTestUtils.getNodeByName(preliminaryTreeNodes, "a1");
|
||||||
BaseTreeNode a2Node = TestPlanTestUtils.getNodeByName(preliminaryTreeNodes, "a2");
|
BaseTreeNode a2Node = TestPlanTestUtils.getNodeByName(preliminaryTreeNodes, "a2");
|
||||||
|
@ -724,96 +842,82 @@ public class TestPlanTests extends BaseTest {
|
||||||
BaseTreeNode a1b1Node = TestPlanTestUtils.getNodeByName(preliminaryTreeNodes, "a1-b1");
|
BaseTreeNode a1b1Node = TestPlanTestUtils.getNodeByName(preliminaryTreeNodes, "a1-b1");
|
||||||
assert a1Node != null & a2Node != null & a3Node != null & a1a1Node != null & a1b1Node != null;
|
assert a1Node != null & a2Node != null & a3Node != null & a1a1Node != null & a1b1Node != null;
|
||||||
|
|
||||||
//查询测试计划列表
|
testPlanTestService.checkTestPlanPage(this.requestPostWithOkAndReturn(
|
||||||
MvcResult pageResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_PAGE, testPlanTableRequest);
|
URL_POST_TEST_PLAN_PAGE, dataRequest).getResponse().getContentAsString(StandardCharsets.UTF_8),
|
||||||
String returnData = pageResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
dataRequest.getCurrent(),
|
||||||
ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class);
|
dataRequest.getPageSize(),
|
||||||
Pager<Object> result = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), Pager.class);
|
1010);
|
||||||
//返回值的页码和当前页码相同
|
testPlanTestService.checkTestPlanPage(this.requestPostWithOkAndReturn(
|
||||||
Assertions.assertEquals(result.getCurrent(), testPlanTableRequest.getCurrent());
|
URL_POST_TEST_PLAN_PAGE, groupRequest).getResponse().getContentAsString(StandardCharsets.UTF_8),
|
||||||
//返回的数据量不超过规定要返回的数据量相同
|
dataRequest.getCurrent(),
|
||||||
Assertions.assertTrue(JSON.parseArray(JSON.toJSONString(result.getList())).size() <= testPlanTableRequest.getPageSize());
|
dataRequest.getPageSize(),
|
||||||
Assertions.assertEquals(result.getTotal(), 1010);
|
2);
|
||||||
|
testPlanTestService.checkTestPlanPage(this.requestPostWithOkAndReturn(
|
||||||
|
URL_POST_TEST_PLAN_PAGE, onlyPlanRequest).getResponse().getContentAsString(StandardCharsets.UTF_8),
|
||||||
|
dataRequest.getCurrent(),
|
||||||
|
dataRequest.getPageSize(),
|
||||||
|
1008);
|
||||||
|
|
||||||
//按照名称倒叙
|
//按照名称倒叙
|
||||||
testPlanTableRequest.setSort(new HashMap<>() {{
|
dataRequest.setSort(new HashMap<>() {{
|
||||||
this.put("name", "desc");
|
this.put("name", "desc");
|
||||||
}});
|
}});
|
||||||
pageResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_PAGE, testPlanTableRequest);
|
testPlanTestService.checkTestPlanPage(this.requestPostWithOkAndReturn(
|
||||||
returnData = pageResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
URL_POST_TEST_PLAN_PAGE, dataRequest).getResponse().getContentAsString(StandardCharsets.UTF_8),
|
||||||
resultHolder = JSON.parseObject(returnData, ResultHolder.class);
|
dataRequest.getCurrent(),
|
||||||
result = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), Pager.class);
|
dataRequest.getPageSize(),
|
||||||
//返回值的页码和当前页码相同
|
1010);
|
||||||
Assertions.assertEquals(result.getCurrent(), testPlanTableRequest.getCurrent());
|
|
||||||
//返回的数据量不超过规定要返回的数据量相同
|
|
||||||
Assertions.assertTrue(JSON.parseArray(JSON.toJSONString(result.getList())).size() <= testPlanTableRequest.getPageSize());
|
|
||||||
Assertions.assertEquals(result.getTotal(), 1010);
|
|
||||||
|
|
||||||
|
|
||||||
//指定模块ID查询 (查询count时,不会因为选择了模块而更改了总量
|
//指定模块ID查询 (查询count时,不会因为选择了模块而更改了总量
|
||||||
testPlanTableRequest.setModuleIds(Arrays.asList(a1Node.getId(), a1a1Node.getId(), a1b1Node.getId()));
|
dataRequest.setModuleIds(Arrays.asList(a1Node.getId(), a1a1Node.getId(), a1b1Node.getId()));
|
||||||
moduleCountResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_MODULE_COUNT, testPlanTableRequest);
|
moduleCountResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_MODULE_COUNT, dataRequest);
|
||||||
moduleCountReturnData = moduleCountResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
moduleCountReturnData = moduleCountResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||||
moduleCountMap = JSON.parseObject(JSON.toJSONString(JSON.parseObject(moduleCountReturnData, ResultHolder.class).getData()), Map.class);
|
moduleCountMap = JSON.parseObject(JSON.toJSONString(JSON.parseObject(moduleCountReturnData, ResultHolder.class).getData()), Map.class);
|
||||||
|
|
||||||
|
testPlanTestService.checkTestPlanPage(this.requestPostWithOkAndReturn(
|
||||||
pageResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_PAGE, testPlanTableRequest);
|
URL_POST_TEST_PLAN_PAGE, dataRequest).getResponse().getContentAsString(StandardCharsets.UTF_8),
|
||||||
returnData = pageResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
dataRequest.getCurrent(),
|
||||||
resultHolder = JSON.parseObject(returnData, ResultHolder.class);
|
dataRequest.getPageSize(),
|
||||||
result = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), Pager.class);
|
910);
|
||||||
//返回值的页码和当前页码相同
|
|
||||||
Assertions.assertEquals(result.getCurrent(), testPlanTableRequest.getCurrent());
|
|
||||||
//返回的数据量不超过规定要返回的数据量相同
|
|
||||||
Assertions.assertTrue(JSON.parseArray(JSON.toJSONString(result.getList())).size() <= testPlanTableRequest.getPageSize());
|
|
||||||
|
|
||||||
|
|
||||||
//测试根据名称模糊查询: Plan_2 预期结果: a1Node下有11条(testPlan_2,testPlan_20~testPlan_29), a1b1Node下有100条(testPlan_200~testPlan_299)
|
//测试根据名称模糊查询: Plan_2 预期结果: a1Node下有11条(testPlan_2,testPlan_20~testPlan_29), a1b1Node下有100条(testPlan_200~testPlan_299)
|
||||||
testPlanTableRequest.setModuleIds(null);
|
dataRequest.setModuleIds(null);
|
||||||
testPlanTableRequest.initKeyword("Plan_2");
|
dataRequest.initKeyword("Plan_2");
|
||||||
moduleCountResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_MODULE_COUNT, testPlanTableRequest);
|
moduleCountResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_MODULE_COUNT, dataRequest);
|
||||||
moduleCountReturnData = moduleCountResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
moduleCountReturnData = moduleCountResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||||
moduleCountMap = JSON.parseObject(JSON.toJSONString(JSON.parseObject(moduleCountReturnData, ResultHolder.class).getData()), Map.class);
|
moduleCountMap = JSON.parseObject(JSON.toJSONString(JSON.parseObject(moduleCountReturnData, ResultHolder.class).getData()), Map.class);
|
||||||
|
long allSize = Long.parseLong(String.valueOf(moduleCountMap.get("all")));
|
||||||
|
testPlanTestService.checkTestPlanPage(this.requestPostWithOkAndReturn(
|
||||||
pageResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_PAGE, testPlanTableRequest);
|
URL_POST_TEST_PLAN_PAGE, dataRequest).getResponse().getContentAsString(StandardCharsets.UTF_8),
|
||||||
returnData = pageResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
dataRequest.getCurrent(),
|
||||||
resultHolder = JSON.parseObject(returnData, ResultHolder.class);
|
dataRequest.getPageSize(),
|
||||||
result = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), Pager.class);
|
allSize);
|
||||||
//返回值的页码和当前页码相同
|
|
||||||
Assertions.assertEquals(result.getCurrent(), testPlanTableRequest.getCurrent());
|
|
||||||
//返回的数据量不超过规定要返回的数据量相同
|
|
||||||
Assertions.assertTrue(JSON.parseArray(JSON.toJSONString(result.getList())).size() <= testPlanTableRequest.getPageSize());
|
|
||||||
|
|
||||||
|
|
||||||
//测试根据名称模糊查询(包含测试组的): Plan_7 预期结果: a1Node下有1条(testPlan_7), a2Node下有10条(testPlan_70~testPlan_79),a1b1Node下有100条(testPlan_700~testPlan_799)
|
//测试根据名称模糊查询(包含测试组的): Plan_7 预期结果: a1Node下有1条(testPlan_7), a2Node下有10条(testPlan_70~testPlan_79),a1b1Node下有100条(testPlan_700~testPlan_799)
|
||||||
testPlanTableRequest.initKeyword("Plan_7");
|
dataRequest.initKeyword("Plan_7");
|
||||||
testPlanTableRequest.setSort(new HashMap<>() {{
|
dataRequest.setSort(new HashMap<>() {{
|
||||||
this.put("num", "asc");
|
this.put("num", "asc");
|
||||||
}});
|
}});
|
||||||
moduleCountResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_MODULE_COUNT, testPlanTableRequest);
|
moduleCountResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_MODULE_COUNT, dataRequest);
|
||||||
moduleCountReturnData = moduleCountResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
moduleCountReturnData = moduleCountResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||||
moduleCountMap = JSON.parseObject(JSON.toJSONString(JSON.parseObject(moduleCountReturnData, ResultHolder.class).getData()), Map.class);
|
moduleCountMap = JSON.parseObject(JSON.toJSONString(JSON.parseObject(moduleCountReturnData, ResultHolder.class).getData()), Map.class);
|
||||||
|
allSize = Long.parseLong(String.valueOf(moduleCountMap.get("all")));
|
||||||
|
testPlanTestService.checkTestPlanPage(this.requestPostWithOkAndReturn(
|
||||||
pageResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_PAGE, testPlanTableRequest);
|
URL_POST_TEST_PLAN_PAGE, dataRequest).getResponse().getContentAsString(StandardCharsets.UTF_8),
|
||||||
returnData = pageResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
dataRequest.getCurrent(),
|
||||||
resultHolder = JSON.parseObject(returnData, ResultHolder.class);
|
dataRequest.getPageSize(),
|
||||||
result = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), Pager.class);
|
allSize);
|
||||||
//返回值的页码和当前页码相同
|
|
||||||
Assertions.assertEquals(result.getCurrent(), testPlanTableRequest.getCurrent());
|
|
||||||
//返回的数据量不超过规定要返回的数据量相同
|
|
||||||
Assertions.assertTrue(JSON.parseArray(JSON.toJSONString(result.getList())).size() <= testPlanTableRequest.getPageSize());
|
|
||||||
|
|
||||||
|
|
||||||
//反例:参数校验(项目ID不存在)
|
//反例:参数校验(项目ID不存在)
|
||||||
testPlanTableRequest.setProjectId(null);
|
dataRequest.setProjectId(null);
|
||||||
this.requestPost(URL_POST_TEST_PLAN_MODULE_COUNT, testPlanTableRequest).andExpect(status().isBadRequest());
|
this.requestPost(URL_POST_TEST_PLAN_MODULE_COUNT, dataRequest).andExpect(status().isBadRequest());
|
||||||
this.requestPost(URL_POST_TEST_PLAN_PAGE, testPlanTableRequest).andExpect(status().isBadRequest());
|
this.requestPost(URL_POST_TEST_PLAN_PAGE, dataRequest).andExpect(status().isBadRequest());
|
||||||
|
|
||||||
//测试权限
|
//测试权限
|
||||||
testPlanTableRequest.setProjectId(DEFAULT_PROJECT_ID);
|
dataRequest.setProjectId(DEFAULT_PROJECT_ID);
|
||||||
this.requestPostPermissionTest(PermissionConstants.TEST_PLAN_READ, URL_POST_TEST_PLAN_MODULE_COUNT, testPlanTableRequest);
|
this.requestPostPermissionTest(PermissionConstants.TEST_PLAN_READ, URL_POST_TEST_PLAN_MODULE_COUNT, dataRequest);
|
||||||
this.requestPostPermissionTest(PermissionConstants.TEST_PLAN_READ, URL_POST_TEST_PLAN_PAGE, testPlanTableRequest);
|
this.requestPostPermissionTest(PermissionConstants.TEST_PLAN_READ, URL_POST_TEST_PLAN_PAGE, dataRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,11 @@ import io.metersphere.project.mapper.ProjectMapper;
|
||||||
import io.metersphere.sdk.constants.*;
|
import io.metersphere.sdk.constants.*;
|
||||||
import io.metersphere.sdk.util.JSON;
|
import io.metersphere.sdk.util.JSON;
|
||||||
import io.metersphere.sdk.util.SubListUtils;
|
import io.metersphere.sdk.util.SubListUtils;
|
||||||
|
import io.metersphere.system.controller.handler.ResultHolder;
|
||||||
import io.metersphere.system.domain.TestPlanModuleExample;
|
import io.metersphere.system.domain.TestPlanModuleExample;
|
||||||
import io.metersphere.system.uid.IDGenerator;
|
import io.metersphere.system.uid.IDGenerator;
|
||||||
import io.metersphere.system.uid.NumGenerator;
|
import io.metersphere.system.uid.NumGenerator;
|
||||||
|
import io.metersphere.system.utils.Pager;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
@ -433,4 +435,16 @@ public class TestPlanTestService {
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void checkTestPlanPage(String returnData, long current, long pageSize, long allData) {
|
||||||
|
ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class);
|
||||||
|
Pager<Object> result = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), Pager.class);
|
||||||
|
//返回值的页码和当前页码相同
|
||||||
|
Assertions.assertEquals(result.getCurrent(), current);
|
||||||
|
//返回的数据量不超过规定要返回的数据量相同
|
||||||
|
Assertions.assertTrue(JSON.parseArray(JSON.toJSONString(result.getList())).size() <= pageSize);
|
||||||
|
if (allData > 0) {
|
||||||
|
Assertions.assertEquals(result.getTotal(), allData);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
package io.metersphere.plan.service.mock;
|
|
||||||
|
|
||||||
import io.metersphere.plan.domain.TestPlan;
|
|
||||||
import io.metersphere.plan.domain.TestPlanConfig;
|
|
||||||
import io.metersphere.plan.service.TestPlanGroupService;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
public class TestPlanGroupServiceImpl implements TestPlanGroupService {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean validateGroup(TestPlan testPlan, TestPlanConfig testPlanConfig) {
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in New Issue