feat(用例评审): 新增用例评审列表查询和增加用例关联接口

This commit is contained in:
guoyuqi 2023-12-01 11:12:40 +08:00 committed by Craftsman
parent b7d117ba79
commit c9a3508278
24 changed files with 1206 additions and 83 deletions

View File

@ -4,6 +4,7 @@ import io.metersphere.validation.groups.*;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.*;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import lombok.Data;
@ -15,6 +16,9 @@ public class CaseReview implements Serializable {
@Size(min = 1, max = 50, message = "{case_review.id.length_range}", groups = {Created.class, Updated.class})
private String id;
@Schema(description = "业务ID")
private Long num;
@Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{case_review.name.not_blank}", groups = {Created.class})
@Size(min = 1, max = 255, message = "{case_review.name.length_range}", groups = {Created.class, Updated.class})
@ -50,6 +54,14 @@ public class CaseReview implements Serializable {
@Schema(description = "评审结束时间")
private Long endTime;
@Schema(description = "用例数", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "{case_review.case_count.not_blank}", groups = {Created.class})
private Integer caseCount;
@Schema(description = "通过率(保留两位小数)", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "{case_review.pass_rate.not_blank}", groups = {Created.class})
private BigDecimal passRate;
@Schema(description = "标签")
private String tags;
@ -72,6 +84,7 @@ public class CaseReview implements Serializable {
public enum Column {
id("id", "id", "VARCHAR", false),
num("num", "num", "BIGINT", false),
name("name", "name", "VARCHAR", true),
moduleId("module_id", "moduleId", "VARCHAR", false),
projectId("project_id", "projectId", "VARCHAR", false),
@ -80,6 +93,8 @@ public class CaseReview implements Serializable {
pos("pos", "pos", "BIGINT", false),
startTime("start_time", "startTime", "BIGINT", false),
endTime("end_time", "endTime", "BIGINT", false),
caseCount("case_count", "caseCount", "INTEGER", false),
passRate("pass_rate", "passRate", "DECIMAL", false),
tags("tags", "tags", "VARCHAR", false),
description("description", "description", "VARCHAR", false),
createTime("create_time", "createTime", "BIGINT", false),

View File

@ -1,5 +1,6 @@
package io.metersphere.functional.domain;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
@ -174,6 +175,66 @@ public class CaseReviewExample {
return (Criteria) this;
}
public Criteria andNumIsNull() {
addCriterion("num is null");
return (Criteria) this;
}
public Criteria andNumIsNotNull() {
addCriterion("num is not null");
return (Criteria) this;
}
public Criteria andNumEqualTo(Long value) {
addCriterion("num =", value, "num");
return (Criteria) this;
}
public Criteria andNumNotEqualTo(Long value) {
addCriterion("num <>", value, "num");
return (Criteria) this;
}
public Criteria andNumGreaterThan(Long value) {
addCriterion("num >", value, "num");
return (Criteria) this;
}
public Criteria andNumGreaterThanOrEqualTo(Long value) {
addCriterion("num >=", value, "num");
return (Criteria) this;
}
public Criteria andNumLessThan(Long value) {
addCriterion("num <", value, "num");
return (Criteria) this;
}
public Criteria andNumLessThanOrEqualTo(Long value) {
addCriterion("num <=", value, "num");
return (Criteria) this;
}
public Criteria andNumIn(List<Long> values) {
addCriterion("num in", values, "num");
return (Criteria) this;
}
public Criteria andNumNotIn(List<Long> values) {
addCriterion("num not in", values, "num");
return (Criteria) this;
}
public Criteria andNumBetween(Long value1, Long value2) {
addCriterion("num between", value1, value2, "num");
return (Criteria) this;
}
public Criteria andNumNotBetween(Long value1, Long value2) {
addCriterion("num not between", value1, value2, "num");
return (Criteria) this;
}
public Criteria andNameIsNull() {
addCriterion("`name` is null");
return (Criteria) this;
@ -704,6 +765,126 @@ public class CaseReviewExample {
return (Criteria) this;
}
public Criteria andCaseCountIsNull() {
addCriterion("case_count is null");
return (Criteria) this;
}
public Criteria andCaseCountIsNotNull() {
addCriterion("case_count is not null");
return (Criteria) this;
}
public Criteria andCaseCountEqualTo(Integer value) {
addCriterion("case_count =", value, "caseCount");
return (Criteria) this;
}
public Criteria andCaseCountNotEqualTo(Integer value) {
addCriterion("case_count <>", value, "caseCount");
return (Criteria) this;
}
public Criteria andCaseCountGreaterThan(Integer value) {
addCriterion("case_count >", value, "caseCount");
return (Criteria) this;
}
public Criteria andCaseCountGreaterThanOrEqualTo(Integer value) {
addCriterion("case_count >=", value, "caseCount");
return (Criteria) this;
}
public Criteria andCaseCountLessThan(Integer value) {
addCriterion("case_count <", value, "caseCount");
return (Criteria) this;
}
public Criteria andCaseCountLessThanOrEqualTo(Integer value) {
addCriterion("case_count <=", value, "caseCount");
return (Criteria) this;
}
public Criteria andCaseCountIn(List<Integer> values) {
addCriterion("case_count in", values, "caseCount");
return (Criteria) this;
}
public Criteria andCaseCountNotIn(List<Integer> values) {
addCriterion("case_count not in", values, "caseCount");
return (Criteria) this;
}
public Criteria andCaseCountBetween(Integer value1, Integer value2) {
addCriterion("case_count between", value1, value2, "caseCount");
return (Criteria) this;
}
public Criteria andCaseCountNotBetween(Integer value1, Integer value2) {
addCriterion("case_count not between", value1, value2, "caseCount");
return (Criteria) this;
}
public Criteria andPassRateIsNull() {
addCriterion("pass_rate is null");
return (Criteria) this;
}
public Criteria andPassRateIsNotNull() {
addCriterion("pass_rate is not null");
return (Criteria) this;
}
public Criteria andPassRateEqualTo(BigDecimal value) {
addCriterion("pass_rate =", value, "passRate");
return (Criteria) this;
}
public Criteria andPassRateNotEqualTo(BigDecimal value) {
addCriterion("pass_rate <>", value, "passRate");
return (Criteria) this;
}
public Criteria andPassRateGreaterThan(BigDecimal value) {
addCriterion("pass_rate >", value, "passRate");
return (Criteria) this;
}
public Criteria andPassRateGreaterThanOrEqualTo(BigDecimal value) {
addCriterion("pass_rate >=", value, "passRate");
return (Criteria) this;
}
public Criteria andPassRateLessThan(BigDecimal value) {
addCriterion("pass_rate <", value, "passRate");
return (Criteria) this;
}
public Criteria andPassRateLessThanOrEqualTo(BigDecimal value) {
addCriterion("pass_rate <=", value, "passRate");
return (Criteria) this;
}
public Criteria andPassRateIn(List<BigDecimal> values) {
addCriterion("pass_rate in", values, "passRate");
return (Criteria) this;
}
public Criteria andPassRateNotIn(List<BigDecimal> values) {
addCriterion("pass_rate not in", values, "passRate");
return (Criteria) this;
}
public Criteria andPassRateBetween(BigDecimal value1, BigDecimal value2) {
addCriterion("pass_rate between", value1, value2, "passRate");
return (Criteria) this;
}
public Criteria andPassRateNotBetween(BigDecimal value1, BigDecimal value2) {
addCriterion("pass_rate not between", value1, value2, "passRate");
return (Criteria) this;
}
public Criteria andTagsIsNull() {
addCriterion("tags is null");
return (Criteria) this;

View File

@ -21,14 +21,14 @@ public class CaseReviewFunctionalCaseArchive implements Serializable {
private String caseId;
@Schema(description = "功能用例快照JSON)")
private String content;
private byte[] content;
private static final long serialVersionUID = 1L;
public enum Column {
reviewId("review_id", "reviewId", "VARCHAR", false),
caseId("case_id", "caseId", "VARCHAR", false),
content("content", "content", "LONGVARCHAR", false);
content("content", "content", "LONGVARBINARY", false);
private static final String BEGINNING_DELIMITER = "`";

View File

@ -6,7 +6,7 @@
<result column="case_id" jdbcType="VARCHAR" property="caseId" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.functional.domain.CaseReviewFunctionalCaseArchive">
<result column="content" jdbcType="LONGVARCHAR" property="content" />
<result column="content" jdbcType="LONGVARBINARY" property="content" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
@ -111,7 +111,7 @@
<insert id="insert" parameterType="io.metersphere.functional.domain.CaseReviewFunctionalCaseArchive">
insert into case_review_functional_case_archive (review_id, case_id, content
)
values (#{reviewId,jdbcType=VARCHAR}, #{caseId,jdbcType=VARCHAR}, #{content,jdbcType=LONGVARCHAR}
values (#{reviewId,jdbcType=VARCHAR}, #{caseId,jdbcType=VARCHAR}, #{content,jdbcType=LONGVARBINARY}
)
</insert>
<insert id="insertSelective" parameterType="io.metersphere.functional.domain.CaseReviewFunctionalCaseArchive">
@ -135,7 +135,7 @@
#{caseId,jdbcType=VARCHAR},
</if>
<if test="content != null">
#{content,jdbcType=LONGVARCHAR},
#{content,jdbcType=LONGVARBINARY},
</if>
</trim>
</insert>
@ -155,7 +155,7 @@
case_id = #{record.caseId,jdbcType=VARCHAR},
</if>
<if test="record.content != null">
content = #{record.content,jdbcType=LONGVARCHAR},
content = #{record.content,jdbcType=LONGVARBINARY},
</if>
</set>
<if test="_parameter != null">
@ -166,7 +166,7 @@
update case_review_functional_case_archive
set review_id = #{record.reviewId,jdbcType=VARCHAR},
case_id = #{record.caseId,jdbcType=VARCHAR},
content = #{record.content,jdbcType=LONGVARCHAR}
content = #{record.content,jdbcType=LONGVARBINARY}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -184,7 +184,7 @@
(review_id, case_id, content)
values
<foreach collection="list" item="item" separator=",">
(#{item.reviewId,jdbcType=VARCHAR}, #{item.caseId,jdbcType=VARCHAR}, #{item.content,jdbcType=LONGVARCHAR}
(#{item.reviewId,jdbcType=VARCHAR}, #{item.caseId,jdbcType=VARCHAR}, #{item.content,jdbcType=LONGVARBINARY}
)
</foreach>
</insert>
@ -205,7 +205,7 @@
#{item.caseId,jdbcType=VARCHAR}
</if>
<if test="'content'.toString() == column.value">
#{item.content,jdbcType=LONGVARCHAR}
#{item.content,jdbcType=LONGVARBINARY}
</if>
</foreach>
)

View File

@ -3,6 +3,7 @@
<mapper namespace="io.metersphere.functional.mapper.CaseReviewMapper">
<resultMap id="BaseResultMap" type="io.metersphere.functional.domain.CaseReview">
<id column="id" jdbcType="VARCHAR" property="id" />
<result column="num" jdbcType="BIGINT" property="num" />
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="module_id" jdbcType="VARCHAR" property="moduleId" />
<result column="project_id" jdbcType="VARCHAR" property="projectId" />
@ -11,6 +12,8 @@
<result column="pos" jdbcType="BIGINT" property="pos" />
<result column="start_time" jdbcType="BIGINT" property="startTime" />
<result column="end_time" jdbcType="BIGINT" property="endTime" />
<result column="case_count" jdbcType="INTEGER" property="caseCount" />
<result column="pass_rate" jdbcType="DECIMAL" property="passRate" />
<result column="tags" jdbcType="VARCHAR" property="tags" />
<result column="description" jdbcType="VARCHAR" property="description" />
<result column="create_time" jdbcType="BIGINT" property="createTime" />
@ -77,8 +80,9 @@
</where>
</sql>
<sql id="Base_Column_List">
id, `name`, module_id, project_id, `status`, review_pass_rule, pos, start_time, end_time,
tags, description, create_time, create_user, update_time, update_user
id, num, `name`, module_id, project_id, `status`, review_pass_rule, pos, start_time,
end_time, case_count, pass_rate, tags, description, create_time, create_user, update_time,
update_user
</sql>
<select id="selectByExample" parameterType="io.metersphere.functional.domain.CaseReviewExample" resultMap="BaseResultMap">
select
@ -111,15 +115,17 @@
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.functional.domain.CaseReview">
insert into case_review (id, `name`, module_id,
project_id, `status`, review_pass_rule,
pos, start_time, end_time,
insert into case_review (id, num, `name`,
module_id, project_id, `status`,
review_pass_rule, pos, start_time,
end_time, case_count, pass_rate,
tags, description, create_time,
create_user, update_time, update_user
)
values (#{id,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{moduleId,jdbcType=VARCHAR},
#{projectId,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR}, #{reviewPassRule,jdbcType=VARCHAR},
#{pos,jdbcType=BIGINT}, #{startTime,jdbcType=BIGINT}, #{endTime,jdbcType=BIGINT},
values (#{id,jdbcType=VARCHAR}, #{num,jdbcType=BIGINT}, #{name,jdbcType=VARCHAR},
#{moduleId,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR},
#{reviewPassRule,jdbcType=VARCHAR}, #{pos,jdbcType=BIGINT}, #{startTime,jdbcType=BIGINT},
#{endTime,jdbcType=BIGINT}, #{caseCount,jdbcType=INTEGER}, #{passRate,jdbcType=DECIMAL},
#{tags,jdbcType=VARCHAR}, #{description,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT},
#{createUser,jdbcType=VARCHAR}, #{updateTime,jdbcType=BIGINT}, #{updateUser,jdbcType=VARCHAR}
)
@ -130,6 +136,9 @@
<if test="id != null">
id,
</if>
<if test="num != null">
num,
</if>
<if test="name != null">
`name`,
</if>
@ -154,6 +163,12 @@
<if test="endTime != null">
end_time,
</if>
<if test="caseCount != null">
case_count,
</if>
<if test="passRate != null">
pass_rate,
</if>
<if test="tags != null">
tags,
</if>
@ -177,6 +192,9 @@
<if test="id != null">
#{id,jdbcType=VARCHAR},
</if>
<if test="num != null">
#{num,jdbcType=BIGINT},
</if>
<if test="name != null">
#{name,jdbcType=VARCHAR},
</if>
@ -201,6 +219,12 @@
<if test="endTime != null">
#{endTime,jdbcType=BIGINT},
</if>
<if test="caseCount != null">
#{caseCount,jdbcType=INTEGER},
</if>
<if test="passRate != null">
#{passRate,jdbcType=DECIMAL},
</if>
<if test="tags != null">
#{tags,jdbcType=VARCHAR},
</if>
@ -233,6 +257,9 @@
<if test="record.id != null">
id = #{record.id,jdbcType=VARCHAR},
</if>
<if test="record.num != null">
num = #{record.num,jdbcType=BIGINT},
</if>
<if test="record.name != null">
`name` = #{record.name,jdbcType=VARCHAR},
</if>
@ -257,6 +284,12 @@
<if test="record.endTime != null">
end_time = #{record.endTime,jdbcType=BIGINT},
</if>
<if test="record.caseCount != null">
case_count = #{record.caseCount,jdbcType=INTEGER},
</if>
<if test="record.passRate != null">
pass_rate = #{record.passRate,jdbcType=DECIMAL},
</if>
<if test="record.tags != null">
tags = #{record.tags,jdbcType=VARCHAR},
</if>
@ -283,6 +316,7 @@
<update id="updateByExample" parameterType="map">
update case_review
set id = #{record.id,jdbcType=VARCHAR},
num = #{record.num,jdbcType=BIGINT},
`name` = #{record.name,jdbcType=VARCHAR},
module_id = #{record.moduleId,jdbcType=VARCHAR},
project_id = #{record.projectId,jdbcType=VARCHAR},
@ -291,6 +325,8 @@
pos = #{record.pos,jdbcType=BIGINT},
start_time = #{record.startTime,jdbcType=BIGINT},
end_time = #{record.endTime,jdbcType=BIGINT},
case_count = #{record.caseCount,jdbcType=INTEGER},
pass_rate = #{record.passRate,jdbcType=DECIMAL},
tags = #{record.tags,jdbcType=VARCHAR},
description = #{record.description,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
@ -304,6 +340,9 @@
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.functional.domain.CaseReview">
update case_review
<set>
<if test="num != null">
num = #{num,jdbcType=BIGINT},
</if>
<if test="name != null">
`name` = #{name,jdbcType=VARCHAR},
</if>
@ -328,6 +367,12 @@
<if test="endTime != null">
end_time = #{endTime,jdbcType=BIGINT},
</if>
<if test="caseCount != null">
case_count = #{caseCount,jdbcType=INTEGER},
</if>
<if test="passRate != null">
pass_rate = #{passRate,jdbcType=DECIMAL},
</if>
<if test="tags != null">
tags = #{tags,jdbcType=VARCHAR},
</if>
@ -351,7 +396,8 @@
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.functional.domain.CaseReview">
update case_review
set `name` = #{name,jdbcType=VARCHAR},
set num = #{num,jdbcType=BIGINT},
`name` = #{name,jdbcType=VARCHAR},
module_id = #{moduleId,jdbcType=VARCHAR},
project_id = #{projectId,jdbcType=VARCHAR},
`status` = #{status,jdbcType=VARCHAR},
@ -359,6 +405,8 @@
pos = #{pos,jdbcType=BIGINT},
start_time = #{startTime,jdbcType=BIGINT},
end_time = #{endTime,jdbcType=BIGINT},
case_count = #{caseCount,jdbcType=INTEGER},
pass_rate = #{passRate,jdbcType=DECIMAL},
tags = #{tags,jdbcType=VARCHAR},
description = #{description,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
@ -369,14 +417,15 @@
</update>
<insert id="batchInsert" parameterType="map">
insert into case_review
(id, `name`, module_id, project_id, `status`, review_pass_rule, pos, start_time,
end_time, tags, description, create_time, create_user, update_time, update_user
)
(id, num, `name`, module_id, project_id, `status`, review_pass_rule, pos, start_time,
end_time, case_count, pass_rate, tags, description, create_time, create_user, update_time,
update_user)
values
<foreach collection="list" item="item" separator=",">
(#{item.id,jdbcType=VARCHAR}, #{item.name,jdbcType=VARCHAR}, #{item.moduleId,jdbcType=VARCHAR},
#{item.projectId,jdbcType=VARCHAR}, #{item.status,jdbcType=VARCHAR}, #{item.reviewPassRule,jdbcType=VARCHAR},
#{item.pos,jdbcType=BIGINT}, #{item.startTime,jdbcType=BIGINT}, #{item.endTime,jdbcType=BIGINT},
(#{item.id,jdbcType=VARCHAR}, #{item.num,jdbcType=BIGINT}, #{item.name,jdbcType=VARCHAR},
#{item.moduleId,jdbcType=VARCHAR}, #{item.projectId,jdbcType=VARCHAR}, #{item.status,jdbcType=VARCHAR},
#{item.reviewPassRule,jdbcType=VARCHAR}, #{item.pos,jdbcType=BIGINT}, #{item.startTime,jdbcType=BIGINT},
#{item.endTime,jdbcType=BIGINT}, #{item.caseCount,jdbcType=INTEGER}, #{item.passRate,jdbcType=DECIMAL},
#{item.tags,jdbcType=VARCHAR}, #{item.description,jdbcType=VARCHAR}, #{item.createTime,jdbcType=BIGINT},
#{item.createUser,jdbcType=VARCHAR}, #{item.updateTime,jdbcType=BIGINT}, #{item.updateUser,jdbcType=VARCHAR}
)
@ -395,6 +444,9 @@
<if test="'id'.toString() == column.value">
#{item.id,jdbcType=VARCHAR}
</if>
<if test="'num'.toString() == column.value">
#{item.num,jdbcType=BIGINT}
</if>
<if test="'name'.toString() == column.value">
#{item.name,jdbcType=VARCHAR}
</if>
@ -419,6 +471,12 @@
<if test="'end_time'.toString() == column.value">
#{item.endTime,jdbcType=BIGINT}
</if>
<if test="'case_count'.toString() == column.value">
#{item.caseCount,jdbcType=INTEGER}
</if>
<if test="'pass_rate'.toString() == column.value">
#{item.passRate,jdbcType=DECIMAL}
</if>
<if test="'tags'.toString() == column.value">
#{item.tags,jdbcType=VARCHAR}
</if>

View File

@ -249,37 +249,43 @@ CREATE INDEX idx_case_id ON functional_case_history (case_id);
CREATE TABLE IF NOT EXISTS case_review
(
`id` VARCHAR(50) NOT NULL COMMENT 'ID',
`name` VARCHAR(255) NOT NULL COMMENT '名称',
`module_id` VARCHAR(50) NOT NULL COMMENT '模块id',
`project_id` VARCHAR(50) NOT NULL COMMENT '项目ID',
`status` VARCHAR(64) NOT NULL DEFAULT 'PREPARE' COMMENT '评审状态:未开始/进行中/已完成/已结束/已归档',
`review_pass_rule` VARCHAR(64) NOT NULL DEFAULT 'SINGLE' COMMENT '通过标准:单人通过/全部通过',
`pos` BIGINT NOT NULL DEFAULT 0 COMMENT '自定义排序间隔5000' ,
`start_time` BIGINT COMMENT '评审开始时间',
`end_time` BIGINT COMMENT '评审结束时间',
`tags` VARCHAR(1000) COMMENT '标签',
`description` VARCHAR(1000) COMMENT '描述',
`create_time` BIGINT NOT NULL COMMENT '创建时间',
`create_user` VARCHAR(50) NOT NULL COMMENT '创建人',
`update_time` BIGINT NOT NULL COMMENT '更新时间',
`update_user` VARCHAR(50) NOT NULL COMMENT '更新人',
PRIMARY KEY (id)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_general_ci COMMENT = '用例评审';
`id` VARCHAR(50) NOT NULL COMMENT 'ID' ,
`num` BIGINT NOT NULL COMMENT '业务ID' ,
`name` VARCHAR(255) NOT NULL COMMENT '名称' ,
`module_id` VARCHAR(50) NOT NULL COMMENT '模块id' ,
`project_id` VARCHAR(50) NOT NULL COMMENT '项目ID' ,
`status` VARCHAR(64) NOT NULL DEFAULT 'PREPARE' COMMENT '评审状态:未开始/进行中/已完成/已结束/已归档' ,
`review_pass_rule` VARCHAR(64) NOT NULL DEFAULT 'SINGLE' COMMENT '通过标准:单人通过/全部通过' ,
`pos` BIGINT NOT NULL DEFAULT 0 COMMENT '自定义排序间隔5000' ,
`start_time` BIGINT COMMENT '评审开始时间' ,
`end_time` BIGINT COMMENT '评审结束时间' ,
`case_count` INT NOT NULL DEFAULT 0 COMMENT '用例数' ,
`pass_rate` DECIMAL(5,2) NOT NULL DEFAULT 0.00 COMMENT '通过率(保留两位小数)' ,
`tags` VARCHAR(1000) COMMENT '标签' ,
`description` VARCHAR(1000) COMMENT '描述' ,
`create_time` BIGINT NOT NULL COMMENT '创建时间' ,
`create_user` VARCHAR(50) NOT NULL COMMENT '创建人' ,
`update_time` BIGINT NOT NULL COMMENT '更新时间' ,
`update_user` VARCHAR(50) NOT NULL COMMENT '更新人' ,
PRIMARY KEY (id)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_general_ci COMMENT = '用例评审';
CREATE INDEX idx_create_user ON case_review (create_user);
CREATE INDEX idx_project_id ON case_review (project_id);
CREATE INDEX idx_name ON case_review (name);
CREATE INDEX idx_status ON case_review (status);
CREATE INDEX idx_review_pass_rule ON case_review (review_pass_rule);
CREATE INDEX idx_create_time ON case_review (create_time desc);
CREATE INDEX idx_update_time ON case_review (update_time desc);
CREATE INDEX idx_update_user ON case_review (update_user);
CREATE INDEX idx_module_id ON case_review (module_id);
CREATE INDEX idx_create_user ON case_review(create_user);
CREATE INDEX idx_project_id ON case_review(project_id);
CREATE INDEX idx_name ON case_review(name);
CREATE INDEX idx_status ON case_review(status);
CREATE INDEX idx_review_pass_rule ON case_review(review_pass_rule);
CREATE INDEX idx_create_time ON case_review(create_time desc);
CREATE INDEX idx_update_time ON case_review(update_time desc);
CREATE INDEX idx_update_user ON case_review(update_user);
CREATE INDEX idx_module_id ON case_review(module_id);
CREATE INDEX idx_pos ON case_review(pos);
CREATE INDEX idx_case_count ON case_review(case_count);
CREATE INDEX idx_pass_rate ON case_review(pass_rate);
CREATE INDEX idx_num ON case_review(num);
CREATE TABLE IF NOT EXISTS case_review_user
@ -317,7 +323,7 @@ CREATE INDEX idx_pos ON case_review_functional_case(pos);
CREATE TABLE IF NOT EXISTS case_review_functional_case_archive(
`review_id` VARCHAR(50) NOT NULL COMMENT '用例评审ID',
`case_id` VARCHAR(50) NOT NULL COMMENT '功能用例ID',
`content` LONGTEXT COMMENT '功能用例快照JSON)'
`content` LONGBLOB COMMENT '功能用例快照JSON)'
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_general_ci COMMENT = '用例评审归档表';

View File

@ -1,6 +1,12 @@
package io.metersphere.functional.controller;
import com.alibaba.excel.util.StringUtils;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.functional.dto.CaseReviewDTO;
import io.metersphere.functional.request.CaseReviewAssociateRequest;
import io.metersphere.functional.request.CaseReviewFollowerRequest;
import io.metersphere.functional.request.CaseReviewPageRequest;
import io.metersphere.functional.request.CaseReviewRequest;
import io.metersphere.functional.service.CaseReviewLogService;
import io.metersphere.functional.service.CaseReviewNoticeService;
@ -11,6 +17,8 @@ import io.metersphere.system.log.annotation.Log;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.notice.annotation.SendNotice;
import io.metersphere.system.notice.constants.NoticeConstants;
import io.metersphere.system.utils.PageUtils;
import io.metersphere.system.utils.Pager;
import io.metersphere.system.utils.SessionUtils;
import io.metersphere.validation.groups.Updated;
import io.swagger.v3.oas.annotations.Operation;
@ -32,6 +40,15 @@ public class CaseReviewController {
@Resource
private CaseReviewService caseReviewService;
@PostMapping("/page")
@Operation(summary = "用例管理-功能用例-用例列表查询")
@RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ)
public Pager<List<CaseReviewDTO>> getFunctionalCasePage(@Validated @RequestBody CaseReviewPageRequest request) {
Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize(),
StringUtils.isNotBlank(request.getSortString()) ? request.getSortString() : "pos desc");
return PageUtils.setPageInfo(page, caseReviewService.getCaseReviewPage(request));
}
@PostMapping("/add")
@Operation(summary = "用例管理-用例评审-创建用例评审")
@Log(type = OperationLogType.ADD, expression = "#msClass.addCaseReviewLog(#request)", msClass = CaseReviewLogService.class)
@ -41,6 +58,14 @@ public class CaseReviewController {
caseReviewService.addCaseReview(request, SessionUtils.getUserId());
}
@PostMapping("/associate")
@Operation(summary = "用例管理-用例评审-关联用例")
@Log(type = OperationLogType.ASSOCIATE, expression = "#msClass.associateCaseLog(#request)", msClass = CaseReviewLogService.class)
@RequiresPermissions(PermissionConstants.CASE_REVIEW_RELEVANCE)
public void associateCase(@Validated @RequestBody CaseReviewAssociateRequest request) {
caseReviewService.associateCase(request, SessionUtils.getUserId());
}
@PostMapping("/edit")
@Operation(summary = "用例管理-用例评审-编辑用例评审")
@Log(type = OperationLogType.UPDATE, expression = "#msClass.updateCaseReviewLog(#request)", msClass = CaseReviewLogService.class)

View File

@ -1,6 +1,32 @@
package io.metersphere.functional.dto;
import io.metersphere.functional.domain.CaseReview;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@Data
public class CaseReviewDTO extends CaseReview {
@Schema(description = "评审人")
private List<String> reviewers;
@Schema(description = "通过数")
private int passCount;
@Schema(description = "不通过数")
private int unPassCount;
@Schema(description = "重新提审数")
private int reReviewedCount;
@Schema(description = "评审中数")
private int underReviewedCount;
@Schema(description = "已评审过得用例数")
private int reviewedCount;
@Schema(description = "评审状态名称")
private String statusName;
}

View File

@ -0,0 +1,12 @@
package io.metersphere.functional.dto;
import io.metersphere.functional.domain.CaseReviewUser;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
public class CaseReviewUserDTO extends CaseReviewUser {
@Schema(description = "用户名")
private String userName;
}

View File

@ -1,6 +1,8 @@
package io.metersphere.functional.mapper;
import io.metersphere.functional.domain.CaseReview;
import io.metersphere.functional.dto.CaseReviewDTO;
import io.metersphere.functional.request.CaseReviewPageRequest;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@ -13,4 +15,7 @@ public interface ExtCaseReviewMapper {
List<CaseReview> checkCaseByModuleIds(@Param("moduleIds") List<String> deleteIds);
Long getPos(@Param("projectId") String projectId);
List<CaseReviewDTO> list(@Param("request") CaseReviewPageRequest request);
}

View File

@ -26,4 +26,271 @@
LIMIT 1;
</select>
<select id="list" resultType="io.metersphere.functional.dto.CaseReviewDTO">
SELECT
*
FROM
case_review
where case_review.project_id = #{request.projectId}
<choose>
<when test='request.searchMode == "AND"'>
AND <include refid="queryWhereCondition"/>
</when>
<when test='request.searchMode == "OR"'>
and (
<include refid="queryWhereCondition"/>
)
</when>
</choose>
1 = 1
</select>
<sql id="queryWhereCondition">
<if test="request.moduleIds != null and request.moduleIds.size() > 0">
case_review.module_id in
<foreach collection="request.moduleIds" item="moduleId" separator="," open="(" close=")">
#{moduleId}
</foreach>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test="request.keyword != null">
(
case_review.name like concat('%', #{request.keyword},'%')
or case_review.num like concat('%', #{request.keyword},'%')
)
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<include refid="filters">
<property name="filter" value="request.filter"/>
</include>
<include refid="combine">
<property name="condition" value="request.combine"/>
<property name="name" value="request.name"/>
<property name="ObjectTags" value="request.combine.tags"/>
<property name="ObjectReviewers" value="request.combine.reviewers"/>
<property name="ObjectModuleIds" value="request.combine.moduleIds"/>
</include>
</sql>
<sql id="queryType">
<choose>
<when test='${searchMode} == "AND"'>
AND
</when>
<when test='${searchMode} == "OR"'>
OR
</when>
</choose>
</sql>
<sql id="filters">
<if test="${filter} != null and ${filter}.size() > 0">
<foreach collection="${filter}.entrySet()" index="key" item="values">
<if test="values != null and values.size() > 0">
<choose>
<when test="key=='status'">
case_review.status in
<include refid="io.metersphere.system.mapper.BaseMapper.filterInWrapper"/>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</when>
<when test="key=='review_pass_rule'">
case_review.review_pass_rule in
<include refid="io.metersphere.system.mapper.BaseMapper.filterInWrapper"/>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</when>
<when test="key=='create_user'">
case_review.create_user in
<include refid="io.metersphere.system.mapper.BaseMapper.filterInWrapper"/>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</when>
<when test="key=='case_reviewer'">
case_review.id in (
select case_review_user.review_id from case_review_user where case_review_user.user_id in
in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
)
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</when>
</choose>
</if>
</foreach>
</if>
</sql>
<sql id="combine">
<if test="request.combine != null">
<if test='${condition}.name != null'>
case_review.name
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.name"/>
</include>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test='${condition}.id != null'>
case_review.num
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.id"/>
</include>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test="${condition}.updateTime != null">
case_review.update_time
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.updateTime"/>
</include>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test="${condition}.createTime != null">
case_review.create_time
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.createTime"/>
</include>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test="${condition}.startTime != null">
case_review.start_time
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.startTime"/>
</include>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test="${condition}.createTime != null">
case_review.end_time
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.endTime"/>
</include>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test='${condition}.tags != null and ${ObjectTags}.operator == "not like"'>
(api_definition.tags is null or api_definition.tags
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.tags"/>
</include>
)
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test='${condition}.tags != null and ${ObjectTags}.operator == "like"'>
api_definition.tags
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.tags"/>
</include>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test="${condition}.caseCount != null">
case_review.case_count
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.caseCount"/>
</include>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test="${condition}.passRate != null">
case_review.pass_rate
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.passRate"/>
</include>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test='${condition}.reviewers != null and ${condition}.reviewers.size() > 0 and ${ObjectReviewers}.operator == "in"'>
case_review.id
<include refid="condition">
<property name="object" value="${condition}.reviewers"/>
</include>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test='${condition}.reviewers != null and ${condition}.reviewers.size() > 0 and ${ObjectReviewers}.operator == "not in"'>
case_review.id
<include refid="condition">
<property name="object" value="${condition}.reviewers"/>
</include>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test='${condition}.moduleIds != null and ${condition}.moduleIds.size() > 0 and ${ObjectModuleIds}.operator == "in"'>
case_review.module_id
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.reviewers"/>
</include>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test='${condition}.moduleIds != null and ${condition}.moduleIds.size() > 0 and ${ObjectModuleIds}.operator == "not in"'>
case_review.module_id
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.reviewers"/>
</include>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
</if>
</sql>
<sql id="condition">
<choose>
<when test='${object}.operator == "in"'>
in ( select review_id from case_review_user where case_review_user.user_id in
<foreach collection="${object}.value" item="v" separator="," open="(" close=")">
#{v}
</foreach>
)
</when>
<when test='${object}.operator == "not in"'>
not in
( select review_id from case_review_user where case_review_user.user_id in
<foreach collection="${object}.value" item="v" separator="," open="(" close=")">
#{v}
</foreach>
)
</when>
</choose>
</sql>
</mapper>

View File

@ -0,0 +1,17 @@
package io.metersphere.functional.mapper;
import io.metersphere.functional.dto.CaseReviewUserDTO;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @author guoyuqi
*/
public interface ExtCaseReviewUserMapper {
List<CaseReviewUserDTO> getReviewUser(@Param("reviewIds") List<String> reviewIds);
}

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="io.metersphere.functional.mapper.ExtCaseReviewUserMapper">
<select id="getReviewUser" resultType="io.metersphere.functional.dto.CaseReviewUserDTO">
SELECT
cu.user_id ,cu.review_id, u.name as userName
FROM
case_review_user cu left join user u on cu.user_id = u.id
WHERE
cu.review_id in
<foreach collection="reviewIds" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
</mapper>

View File

@ -0,0 +1,37 @@
package io.metersphere.functional.request;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* @author guoyuqi
*/
@Data
public class CaseReviewAssociateRequest implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "用例评审id", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{case_review_associate_request.case_review_id.not_blank}")
private String reviewId;
@Schema(description = "项目id", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{case_review_associate_request.project_id.not_blank}")
private String projectId;
@Schema(description = "功能用例id", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "{case_review_associate_request.case_ids.not_empty}")
private List<String> caseIds;
@Schema(description = "评审人")
@NotEmpty(message = "{case_review_associate_request.user_ids.not_empty}")
private List<String> reviewers;
}

View File

@ -0,0 +1,21 @@
package io.metersphere.functional.request;
import io.metersphere.system.dto.sdk.BasePageRequest;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
@Data
public class CaseReviewPageRequest extends BasePageRequest implements Serializable {
@Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{functional_case.project_id.not_blank}")
private String projectId;
@Schema(description = "模块id")
private List<String> moduleIds;
}

View File

@ -1,7 +1,11 @@
package io.metersphere.functional.service;
import io.metersphere.functional.domain.CaseReview;
import io.metersphere.functional.domain.FunctionalCase;
import io.metersphere.functional.domain.FunctionalCaseExample;
import io.metersphere.functional.mapper.CaseReviewMapper;
import io.metersphere.functional.mapper.FunctionalCaseMapper;
import io.metersphere.functional.request.CaseReviewAssociateRequest;
import io.metersphere.functional.request.CaseReviewRequest;
import io.metersphere.sdk.constants.HttpMethodConstants;
import io.metersphere.sdk.util.JSON;
@ -9,9 +13,13 @@ import io.metersphere.system.log.constants.OperationLogModule;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.log.dto.LogDTO;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
/**
* @author guoyuqi
*/
@ -22,6 +30,9 @@ public class CaseReviewLogService {
@Resource
private CaseReviewMapper caseReviewMapper;
@Resource
private FunctionalCaseMapper functionalCaseMapper;
/**
* 新增用例评审 日志
*
@ -69,4 +80,35 @@ public class CaseReviewLogService {
dto.setOriginalValue(JSON.toJSONBytes(caseReview));
return dto;
}
public List<LogDTO> associateCaseLog(CaseReviewAssociateRequest request){
CaseReview caseReview = caseReviewMapper.selectByPrimaryKey(request.getReviewId());
if (caseReview ==null) {
return null;
}
List<LogDTO> dtoList = new ArrayList<>();
List<String> caseIds = request.getCaseIds();
FunctionalCaseExample functionalCaseExample = new FunctionalCaseExample();
functionalCaseExample.createCriteria().andIdIn(caseIds);
List<FunctionalCase> functionalCases = functionalCaseMapper.selectByExample(functionalCaseExample);
if (CollectionUtils.isEmpty(functionalCases)) {
return null;
}
for (FunctionalCase functionalCase : functionalCases) {
LogDTO dto = new LogDTO(
caseReview.getProjectId(),
null,
caseReview.getId(),
caseReview.getCreateUser(),
OperationLogType.ASSOCIATE.name(),
OperationLogModule.CASE_REVIEW,
functionalCase.getName());
dto.setPath("/case/review/associate");
dto.setMethod(HttpMethodConstants.POST.name());
dto.setOriginalValue(JSON.toJSONBytes(functionalCase));
}
return dtoList;
}
}

View File

@ -4,17 +4,24 @@ package io.metersphere.functional.service;
import io.metersphere.functional.constants.CaseReviewStatus;
import io.metersphere.functional.constants.FunctionalCaseReviewStatus;
import io.metersphere.functional.domain.*;
import io.metersphere.functional.dto.CaseReviewDTO;
import io.metersphere.functional.dto.CaseReviewUserDTO;
import io.metersphere.functional.mapper.*;
import io.metersphere.functional.request.CaseReviewAssociateRequest;
import io.metersphere.functional.request.CaseReviewPageRequest;
import io.metersphere.functional.request.CaseReviewRequest;
import io.metersphere.functional.result.CaseManagementResultCode;
import io.metersphere.sdk.constants.ApplicationNumScope;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.domain.User;
import io.metersphere.system.mapper.ExtUserMapper;
import io.metersphere.system.uid.IDGenerator;
import io.metersphere.system.uid.NumGenerator;
import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
@ -22,7 +29,12 @@ import org.mybatis.spring.SqlSessionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 用例评审表服务实现类
@ -47,6 +59,119 @@ public class CaseReviewService {
private CaseReviewUserMapper caseReviewUserMapper;
@Resource
private ExtUserMapper extUserMapper;
@Resource
private CaseReviewFunctionalCaseMapper caseReviewFunctionalCaseMapper;
@Resource
private ExtCaseReviewUserMapper extCaseReviewUserMapper;
/**
* 获取用例评审列表
*
* @param request request
* @return CaseReviewDTO
*/
public List<CaseReviewDTO> getCaseReviewPage(CaseReviewPageRequest request) {
List<CaseReviewDTO> list = extCaseReviewMapper.list(request);
if (CollectionUtils.isEmpty(list)) {
return new ArrayList<>();
}
List<String> reviewIds = list.stream().map(CaseReview::getId).toList();
Map<String, List<CaseReviewFunctionalCase>> reviewCaseMap = getReviewCaseMap(reviewIds);
Map<String, List<CaseReviewUserDTO>> reviewUserMap = getReviewUserMap(reviewIds);
for (CaseReviewDTO caseReviewDTO : list) {
buildCaseReviewDTO(caseReviewDTO, reviewCaseMap, reviewUserMap);
}
return list;
}
/**
* 通过 reviewCaseMap reviewUserMap 补充 用例评审的其他属性
*
* @param caseReviewDTO caseReviewDTO
* @param reviewCaseMap 用例和评审的关系map
* @param reviewUserMap 评审和评审人的关系map
*/
private static void buildCaseReviewDTO(CaseReviewDTO caseReviewDTO, Map<String, List<CaseReviewFunctionalCase>> reviewCaseMap, Map<String, List<CaseReviewUserDTO>> reviewUserMap) {
List<CaseReviewFunctionalCase> caseReviewFunctionalCaseList = reviewCaseMap.get(caseReviewDTO.getId());
if (CollectionUtils.isEmpty(caseReviewFunctionalCaseList)) {
caseReviewDTO.setPassCount(0);
caseReviewDTO.setUnPassCount(0);
caseReviewDTO.setReReviewedCount(0);
caseReviewDTO.setUnderReviewedCount(0);
caseReviewDTO.setReviewedCount(0);
} else {
buildAboutCaseCount(caseReviewDTO, caseReviewFunctionalCaseList);
}
List<CaseReviewUserDTO> caseReviewUserDTOS = reviewUserMap.get(caseReviewDTO.getId());
List<String> userNames = caseReviewUserDTOS.stream().map(CaseReviewUserDTO::getUserName).toList();
caseReviewDTO.setReviewers(userNames);
caseReviewDTO.setStatusName(CaseReviewStatus.valueOf(caseReviewDTO.getStatus()).getName());
}
/**
* 构建用例相关的各种数量
* @param caseReviewDTO 用例评审
* @param caseReviewFunctionalCaseList 用例和评审相关联的集合
*/
private static void buildAboutCaseCount(CaseReviewDTO caseReviewDTO, List<CaseReviewFunctionalCase> caseReviewFunctionalCaseList) {
Map<String, List<CaseReviewFunctionalCase>> statusCaseMap = caseReviewFunctionalCaseList.stream().collect(Collectors.groupingBy(CaseReviewFunctionalCase::getStatus));
List<CaseReviewFunctionalCase> passList = statusCaseMap.get(FunctionalCaseReviewStatus.PASS.toString());
if (passList == null) {
passList = new ArrayList<>();
}
caseReviewDTO.setPassCount(passList.size());
List<CaseReviewFunctionalCase> unPassList = statusCaseMap.get(FunctionalCaseReviewStatus.UN_PASS.toString());
if (unPassList == null) {
unPassList = new ArrayList<>();
}
caseReviewDTO.setUnPassCount(unPassList.size());
List<CaseReviewFunctionalCase> reReviewedList = statusCaseMap.get(FunctionalCaseReviewStatus.RE_REVIEWED.toString());
if (reReviewedList == null) {
reReviewedList = new ArrayList<>();
}
caseReviewDTO.setReReviewedCount(reReviewedList.size());
List<CaseReviewFunctionalCase> underReviewedList = statusCaseMap.get(FunctionalCaseReviewStatus.UNDER_REVIEWED.toString());
if (underReviewedList == null) {
underReviewedList = new ArrayList<>();
}
caseReviewDTO.setUnderReviewedCount(underReviewedList.size());
caseReviewDTO.setReviewedCount(caseReviewDTO.getPassCount() + caseReviewDTO.getUnPassCount());
}
/**
* 通过评审ids获取评审和评审人的关系map
*
* @param reviewIds 评审ids
* @return Map
*/
private Map<String, List<CaseReviewUserDTO>> getReviewUserMap(List<String> reviewIds) {
List<CaseReviewUserDTO> reviewUser = extCaseReviewUserMapper.getReviewUser(reviewIds);
return reviewUser.stream().collect(Collectors.groupingBy(CaseReviewUserDTO::getReviewId));
}
/**
* 通过评审ids获取用例和评审的关系map
*
* @param reviewIds 评审ids
* @return Map
*/
private Map<String, List<CaseReviewFunctionalCase>> getReviewCaseMap(List<String> reviewIds) {
CaseReviewFunctionalCaseExample caseReviewFunctionalCaseExample = new CaseReviewFunctionalCaseExample();
caseReviewFunctionalCaseExample.createCriteria().andReviewIdIn(reviewIds);
List<CaseReviewFunctionalCase> caseReviewFunctionalCases = caseReviewFunctionalCaseMapper.selectByExample(caseReviewFunctionalCaseExample);
return caseReviewFunctionalCases.stream().collect(Collectors.groupingBy(CaseReviewFunctionalCase::getReviewId));
}
/**
* 添加用例评审
@ -60,21 +185,47 @@ public class CaseReviewService {
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
CaseReviewUserMapper mapper = sqlSession.getMapper(CaseReviewUserMapper.class);
CaseReviewFunctionalCaseMapper caseReviewFunctionalCaseMapper = sqlSession.getMapper(CaseReviewFunctionalCaseMapper.class);
CaseReviewFunctionalCaseUserMapper caseReviewFunctionalCaseUserMapper = sqlSession.getMapper(CaseReviewFunctionalCaseUserMapper.class);
try {
//保存和评审人的关系
addCaseReviewUser(request, caseReviewId, mapper);
//保存和用例的关系
addCaseReviewFunctionalCase(request, userId, caseReviewId, caseReviewFunctionalCaseMapper);
addCaseReviewFunctionalCase(request.getCaseIds(), request.getProjectId(), userId, caseReviewId, caseReviewFunctionalCaseMapper);
//保存用例和用例评审人的关系
addCaseReviewFunctionalCaseUser(request.getCaseIds(), request.getReviewers(), caseReviewId, caseReviewFunctionalCaseUserMapper);
sqlSession.flushStatements();
} finally {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
}
/**
* 保存用例和用例评审人的关系
*
* @param caseIds caseIds
* @param reviewers reviewers
* @param caseReviewId 当前用例评审id
* @param caseReviewFunctionalCaseUserMapper mapper
*/
private static void addCaseReviewFunctionalCaseUser(List<String> caseIds, List<String> reviewers, String caseReviewId, CaseReviewFunctionalCaseUserMapper caseReviewFunctionalCaseUserMapper) {
if (CollectionUtils.isNotEmpty(caseIds)) {
caseIds.forEach(caseId -> {
reviewers.forEach(reviewer -> {
CaseReviewFunctionalCaseUser caseReviewFunctionalCaseUser = new CaseReviewFunctionalCaseUser();
caseReviewFunctionalCaseUser.setCaseId(caseId);
caseReviewFunctionalCaseUser.setUserId(reviewer);
caseReviewFunctionalCaseUser.setReviewId(caseReviewId);
caseReviewFunctionalCaseUserMapper.insert(caseReviewFunctionalCaseUser);
});
});
}
}
/**
* 编辑用例评审
*
* @param request 页面参数
* @param userId 当前操作人
* @param userId 当前操作人
*/
public void editCaseReview(CaseReviewRequest request, String userId) {
String reviewId = request.getId();
@ -129,24 +280,27 @@ public class CaseReviewService {
/**
* 获取具有评审权限的用户
*
* @param projectId projectId
* @param keyword 查询关键字根据邮箱和用户名查询
* @param keyword 查询关键字根据邮箱和用户名查询
* @return List<User>
*/
public List<User> getReviewUserList(String projectId, String keyword) {
return extUserMapper.getUserByPermission(projectId, keyword, PermissionConstants.CASE_REVIEW_REVIEW);
return extUserMapper.getUserByPermission(projectId, keyword, PermissionConstants.CASE_REVIEW_REVIEW);
}
/**
* 新增用例评审
* @param request request
* @param userId 当前操作人
*
* @param request request
* @param userId 当前操作人
* @param caseReviewId 用例评审id
*/
private void addCaseReview(CaseReviewRequest request, String userId, String caseReviewId) {
CaseReview caseReview = new CaseReview();
caseReview.setId(caseReviewId);
caseReview.setNum(getNextNum(request.getProjectId()));
caseReview.setProjectId(request.getProjectId());
caseReview.setName(request.getName());
caseReview.setModuleId(request.getModuleId());
@ -156,6 +310,12 @@ public class CaseReviewService {
if (CollectionUtils.isNotEmpty(request.getTags())) {
caseReview.setTags(JSON.toJSONString(request.getTags()));
}
caseReview.setPassRate(BigDecimal.valueOf(0.00));
if (CollectionUtils.isEmpty(request.getCaseIds())) {
caseReview.setCaseCount(0);
} else {
caseReview.setCaseCount(request.getCaseIds().size());
}
caseReview.setStartTime(request.getStartTime());
caseReview.setEndTime(request.getEndTime());
caseReview.setCreateTime(System.currentTimeMillis());
@ -170,17 +330,17 @@ public class CaseReviewService {
*
* @param caseReviewId 用例评审id
*/
private void checkCaseReview(String caseReviewId) {
private CaseReview checkCaseReview(String caseReviewId) {
CaseReviewExample caseReviewExample = new CaseReviewExample();
caseReviewExample.createCriteria().andIdEqualTo(caseReviewId);
CaseReview caseReview = caseReviewMapper.selectByPrimaryKey(caseReviewId);
if (caseReview == null) {
throw new MSException(CaseManagementResultCode.CASE_REVIEW_NOT_FOUND);
}
return caseReview;
}
/**
*
* @param projectId 项目id
* @return pos
*/
@ -189,16 +349,26 @@ public class CaseReviewService {
return (pos == null ? 0 : pos) + POS_STEP;
}
/**
* @param projectId 项目id
* @return num
*/
public long getNextNum(String projectId) {
return NumGenerator.nextNum(projectId, ApplicationNumScope.CASE_MANAGEMENT);
}
/**
* 保存用例评审和功能用例的关系
* @param request request
* @param userId 当前操作人
* @param caseReviewId 用例评审id
*
* @param caseIds 功能用例Ids
* @param projectId 项目ID
* @param userId 当前操作人
* @param caseReviewId 用例评审id
* @param caseReviewFunctionalCaseMapper caseReviewFunctionalCaseMapper
*/
private void addCaseReviewFunctionalCase(CaseReviewRequest request, String userId, String caseReviewId, CaseReviewFunctionalCaseMapper caseReviewFunctionalCaseMapper) {
if (CollectionUtils.isNotEmpty(request.getCaseIds())) {
request.getReviewers().forEach(caseId -> {
private void addCaseReviewFunctionalCase(List<String> caseIds, String projectId, String userId, String caseReviewId, CaseReviewFunctionalCaseMapper caseReviewFunctionalCaseMapper) {
if (CollectionUtils.isNotEmpty(caseIds)) {
caseIds.forEach(caseId -> {
CaseReviewFunctionalCase caseReviewFunctionalCase = new CaseReviewFunctionalCase();
caseReviewFunctionalCase.setReviewId(caseReviewId);
caseReviewFunctionalCase.setCaseId(caseId);
@ -207,7 +377,7 @@ public class CaseReviewService {
caseReviewFunctionalCase.setCreateTime(System.currentTimeMillis());
caseReviewFunctionalCase.setUpdateTime(System.currentTimeMillis());
caseReviewFunctionalCase.setId(IDGenerator.nextStr());
caseReviewFunctionalCase.setPos(getNextPos(request.getProjectId()));
caseReviewFunctionalCase.setPos(getNextPos(projectId));
caseReviewFunctionalCaseMapper.insert(caseReviewFunctionalCase);
});
}
@ -215,8 +385,9 @@ public class CaseReviewService {
/**
* 保存用例评审和评审人的关系
* @param request request
* @param caseReviewId 用例评审
*
* @param request request
* @param caseReviewId 用例评审
* @param caseReviewUserMapper caseReviewUserMapper
*/
private static void addCaseReviewUser(CaseReviewRequest request, String caseReviewId, CaseReviewUserMapper caseReviewUserMapper) {
@ -228,4 +399,42 @@ public class CaseReviewService {
});
}
/**
* 关联用例
* @param request 页面参数
* @param userId 当前操作人
*/
public void associateCase(CaseReviewAssociateRequest request, String userId) {
String caseReviewId = request.getReviewId();
CaseReview caseReviewExist = checkCaseReview(caseReviewId);
CaseReviewFunctionalCaseExample caseReviewFunctionalCaseExample = new CaseReviewFunctionalCaseExample();
caseReviewFunctionalCaseExample.createCriteria().andReviewIdEqualTo(caseReviewId);
List<CaseReviewFunctionalCase> caseReviewFunctionalCases = caseReviewFunctionalCaseMapper.selectByExample(caseReviewFunctionalCaseExample);
List<String> castIds = caseReviewFunctionalCases.stream().map(CaseReviewFunctionalCase::getCaseId).toList();
List<String> caseRealIds = request.getCaseIds().stream().filter(t -> !castIds.contains(t)).toList();
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
CaseReviewFunctionalCaseMapper caseReviewFunctionalCaseMapper = sqlSession.getMapper(CaseReviewFunctionalCaseMapper.class);
CaseReviewFunctionalCaseUserMapper caseReviewFunctionalCaseUserMapper = sqlSession.getMapper(CaseReviewFunctionalCaseUserMapper.class);
try {
//保存和用例的关系
addCaseReviewFunctionalCase(caseRealIds, request.getProjectId(), userId, caseReviewId, caseReviewFunctionalCaseMapper);
//保存用例和用例评审人的关系
addCaseReviewFunctionalCaseUser(caseRealIds, request.getReviewers(), caseReviewId, caseReviewFunctionalCaseUserMapper);
sqlSession.flushStatements();
} finally {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
List<CaseReviewFunctionalCase> passList = caseReviewFunctionalCases.stream().filter(t -> StringUtils.equalsIgnoreCase(t.getStatus(), FunctionalCaseReviewStatus.PASS.toString())).toList();
CaseReview caseReview = new CaseReview();
caseReview.setId(caseReviewId);
//更新用例数量
caseReview.setCaseCount(caseReviewExist.getCaseCount()+caseRealIds.size());
//通过率
BigDecimal passCount = BigDecimal.valueOf(passList.size());
BigDecimal totalCount = BigDecimal.valueOf(caseReview.getCaseCount());
BigDecimal passRate = passCount.divide(totalCount,2, RoundingMode.HALF_UP);
caseReview.setPassRate(passRate);
caseReviewMapper.updateByPrimaryKeySelective(caseReview);
}
}

View File

@ -1,12 +1,13 @@
package io.metersphere.functional.controller;
import io.metersphere.functional.constants.CaseReviewPassRule;
import io.metersphere.functional.constants.FunctionalCaseReviewStatus;
import io.metersphere.functional.domain.*;
import io.metersphere.functional.mapper.CaseReviewFollowerMapper;
import io.metersphere.functional.mapper.CaseReviewFunctionalCaseMapper;
import io.metersphere.functional.mapper.CaseReviewMapper;
import io.metersphere.functional.mapper.CaseReviewUserMapper;
import io.metersphere.functional.dto.CaseReviewDTO;
import io.metersphere.functional.mapper.*;
import io.metersphere.functional.request.CaseReviewAssociateRequest;
import io.metersphere.functional.request.CaseReviewFollowerRequest;
import io.metersphere.functional.request.CaseReviewPageRequest;
import io.metersphere.functional.request.CaseReviewRequest;
import io.metersphere.project.domain.Notification;
import io.metersphere.project.domain.NotificationExample;
@ -16,7 +17,9 @@ import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.handler.ResultHolder;
import io.metersphere.system.domain.User;
import io.metersphere.system.notice.constants.NoticeConstants;
import io.metersphere.system.utils.Pager;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
@ -28,8 +31,8 @@ import org.springframework.test.web.servlet.MvcResult;
import org.testcontainers.shaded.org.apache.commons.lang3.StringUtils;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ -45,6 +48,9 @@ public class CaseReviewControllerTests extends BaseTest {
private static final String ADD_CASE_REVIEW = "/case/review/add";
private static final String EDIT_CASE_REVIEW = "/case/review/edit";
private static final String PAGE_CASE_REVIEW = "/case/review/page";
private static final String ASSOCIATE_CASE_REVIEW = "/case/review/associate";
private static final String FOLLOW_CASE_REVIEW = "/case/review/edit/follower";
private static final String CASE_REVIEWER_LIST = "/case/review/user-option/";
@ -59,6 +65,8 @@ public class CaseReviewControllerTests extends BaseTest {
@Resource
private CaseReviewFunctionalCaseMapper caseReviewFunctionalCaseMapper;
@Resource
private CaseReviewFunctionalCaseUserMapper caseReviewFunctionalCaseUserMapper;
@Resource
private NotificationMapper notificationMapper;
@Test
@ -242,5 +250,166 @@ public class CaseReviewControllerTests extends BaseTest {
Assertions.assertFalse(list.isEmpty());
}
@Test
@Order(10)
public void associateCaseSuccess() throws Exception {
List<CaseReview> caseReviews = getCaseReviews("创建评审更新1");
Assertions.assertEquals(1, caseReviews.size());
String caseReviewId = caseReviews.get(0).getId();
CaseReviewAssociateRequest caseReviewAssociateRequest = new CaseReviewAssociateRequest();
caseReviewAssociateRequest.setProjectId(projectId);
caseReviewAssociateRequest.setReviewId(caseReviewId);
List<String>caseIds = new ArrayList<>();
caseIds.add("CASE_REVIEW_TEST_GYQ_ID2");
caseIds.add("CASE_REVIEW_TEST_GYQ_ID3");
caseIds.add("CASE_REVIEW_TEST_GYQ_ID4");
caseIds.add("CASE_REVIEW_TEST_GYQ_ID5");
caseIds.add("CASE_REVIEW_TEST_GYQ_ID6");
caseReviewAssociateRequest.setCaseIds(caseIds);
List<String>userIds = new ArrayList<>();
userIds.add("gyq_review_test");
userIds.add("gyq_review_test2");
caseReviewAssociateRequest.setReviewers(userIds);
this.requestPostWithOk(ASSOCIATE_CASE_REVIEW, caseReviewAssociateRequest);
CaseReviewFunctionalCaseExample caseReviewFunctionalCaseExample = new CaseReviewFunctionalCaseExample();
caseReviewFunctionalCaseExample.createCriteria().andReviewIdEqualTo(caseReviewId);
List<CaseReviewFunctionalCase> caseReviewFunctionalCases = caseReviewFunctionalCaseMapper.selectByExample(caseReviewFunctionalCaseExample);
List<String> castIds = caseReviewFunctionalCases.stream().map(CaseReviewFunctionalCase::getCaseId).toList();
Assertions.assertTrue(CollectionUtils.isNotEmpty(castIds));
CaseReviewFunctionalCaseUserExample caseReviewFunctionalCaseUserExample = new CaseReviewFunctionalCaseUserExample();
caseReviewFunctionalCaseUserExample.createCriteria().andReviewIdEqualTo(caseReviewId);
List<CaseReviewFunctionalCaseUser> caseReviewFunctionalCaseUsers = caseReviewFunctionalCaseUserMapper.selectByExample(caseReviewFunctionalCaseUserExample);
List<String> userIdList = caseReviewFunctionalCaseUsers.stream().map(CaseReviewFunctionalCaseUser::getUserId).toList();
Assertions.assertTrue(userIdList.contains("gyq_review_test"));
Assertions.assertTrue(userIdList.contains("gyq_review_test2"));
}
@Test
@Order(11)
public void associateCaseFalse() throws Exception {
CaseReviewAssociateRequest caseReviewAssociateRequest = new CaseReviewAssociateRequest();
caseReviewAssociateRequest.setProjectId(projectId);
caseReviewAssociateRequest.setReviewId("caseReviewIdXXXX");
List<String>caseIds = new ArrayList<>();
caseIds.add("CASE_REVIEW_TEST_GYQ_ID2");
caseReviewAssociateRequest.setCaseIds(caseIds);
List<String>userIds = new ArrayList<>();
userIds.add("gyq_review_test");
userIds.add("gyq_review_test2");
caseReviewAssociateRequest.setReviewers(userIds);
this.requestPost(ASSOCIATE_CASE_REVIEW, caseReviewAssociateRequest).andExpect(status().is5xxServerError());
}
@Test
@Order(12)
public void getPageSuccess() throws Exception {
List<CaseReview> caseReviews = getCaseReviews("创建评审更新1");
Assertions.assertEquals(1, caseReviews.size());
Map<String, Object> caseReviewCombine = buildRequestCombine();
CaseReviewPageRequest request = new CaseReviewPageRequest();
Map<String, List<String>> filters = new HashMap<>();
filters.put("status", Arrays.asList("PREPARED", "UNDERWAY","COMPLETED", "ARCHIVED"));
request.setFilter(filters);
request.setCombine(caseReviewCombine);
request.setProjectId(projectId);
request.setKeyword("评审更新");
request.setCurrent(1);
request.setPageSize(10);
MvcResult mvcResult = this.requestPostWithOkAndReturn(PAGE_CASE_REVIEW, request);
// 获取返回值
String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class);
// 返回请求正常
Assertions.assertNotNull(resultHolder);
Pager<?> pageData = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), Pager.class);
// 返回值不为空
Assertions.assertNotNull(pageData);
// 返回值的页码和当前页码相同
Assertions.assertEquals(pageData.getCurrent(), request.getCurrent());
// 返回的数据量不超过规定要返回的数据量相同
Assertions.assertTrue(JSON.parseArray(JSON.toJSONString(pageData.getList())).size() <= request.getPageSize());
CaseReviewFunctionalCaseExample caseReviewFunctionalCaseExample = new CaseReviewFunctionalCaseExample();
caseReviewFunctionalCaseExample.createCriteria().andReviewIdEqualTo(caseReviews.get(0).getId());
List<CaseReviewFunctionalCase> caseReviewFunctionalCases = caseReviewFunctionalCaseMapper.selectByExample(caseReviewFunctionalCaseExample);
Map<String, CaseReviewFunctionalCase> caseReviewFunctionalCaseMap = caseReviewFunctionalCases.stream().collect(Collectors.toMap(CaseReviewFunctionalCase::getCaseId, t -> t));
caseReviewFunctionalCaseMap.forEach((k,v)->{
switch (k) {
case "CASE_REVIEW_TEST_GYQ_ID2" -> v.setStatus(FunctionalCaseReviewStatus.RE_REVIEWED.toString());
case "CASE_REVIEW_TEST_GYQ_ID3" -> v.setStatus(FunctionalCaseReviewStatus.UNDER_REVIEWED.toString());
case "CASE_REVIEW_TEST_GYQ_ID4" -> v.setStatus(FunctionalCaseReviewStatus.PASS.toString());
case "CASE_REVIEW_TEST_GYQ_ID5" -> v.setStatus(FunctionalCaseReviewStatus.UN_PASS.toString());
default -> v.setStatus(FunctionalCaseReviewStatus.UN_REVIEWED.toString());
}
caseReviewFunctionalCaseMapper.updateByPrimaryKeySelective(v);
});
request = new CaseReviewPageRequest();
filters = new HashMap<>();
filters.put("status", Arrays.asList("PREPARED", "UNDERWAY","COMPLETED", "ARCHIVED"));
request.setFilter(filters);
request.setCombine(caseReviewCombine);
request.setProjectId(projectId);
request.setKeyword("评审更新");
request.setCurrent(1);
request.setPageSize(10);
mvcResult = this.requestPostWithOkAndReturn(PAGE_CASE_REVIEW, request);
// 获取返回值
returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
resultHolder = JSON.parseObject(returnData, ResultHolder.class);
// 返回请求正常
Assertions.assertNotNull(resultHolder);
pageData = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), Pager.class);
// 返回值不为空
Assertions.assertNotNull(pageData);
// 返回值的页码和当前页码相同
Assertions.assertEquals(pageData.getCurrent(), request.getCurrent());
// 返回的数据量不超过规定要返回的数据量相同
Assertions.assertTrue(JSON.parseArray(JSON.toJSONString(pageData.getList())).size() <= request.getPageSize());
List<CaseReviewDTO> caseReviewDTOS = JSON.parseArray(JSON.toJSONString(pageData.getList()), CaseReviewDTO.class);
List<CaseReviewDTO> caseReviewOne = caseReviewDTOS.stream().filter(t -> StringUtils.equals(t.getName(), "创建评审更新1")).toList();
Assertions.assertTrue(caseReviewOne.get(0).getPassCount()>0);
Assertions.assertTrue(caseReviewOne.get(0).getUnPassCount()>0);
Assertions.assertTrue(caseReviewOne.get(0).getUnderReviewedCount()>0);
Assertions.assertTrue(caseReviewOne.get(0).getReReviewedCount()>0);
Assertions.assertTrue(caseReviewOne.get(0).getReviewedCount()>0);
request = new CaseReviewPageRequest();
filters = new HashMap<>();
filters.put("status", Arrays.asList("UNDERWAY","COMPLETED", "ARCHIVED"));
request.setFilter(filters);
request.setCombine(caseReviewCombine);
request.setProjectId(projectId);
request.setKeyword("评审更新");
request.setCurrent(1);
request.setPageSize(10);
mvcResult = this.requestPostWithOkAndReturn(PAGE_CASE_REVIEW, request);
// 获取返回值
returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
resultHolder = JSON.parseObject(returnData, ResultHolder.class);
// 返回请求正常
Assertions.assertNotNull(resultHolder);
pageData = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), Pager.class);
// 返回值不为空
Assertions.assertNotNull(pageData);
// 返回值的页码和当前页码相同
Assertions.assertEquals(pageData.getCurrent(), request.getCurrent());
// 返回的数据量不超过规定要返回的数据量相同
Assertions.assertTrue(JSON.parseArray(JSON.toJSONString(pageData.getList())).size() <= request.getPageSize());
caseReviewDTOS = JSON.parseArray(JSON.toJSONString(pageData.getList()), CaseReviewDTO.class);
Assertions.assertTrue(CollectionUtils.isEmpty(caseReviewDTOS));
}
/**
* 生成高级搜索参数
* @return combine param
*/
private Map<String, Object> buildRequestCombine() {
Map<String, Object> map = new HashMap<>();
map.put("reviewers", Map.of("operator", "in", "value", List.of("admin")));
return map;
}
}

View File

@ -688,6 +688,7 @@ public class CaseReviewModuleControllerTests extends BaseTest {
CaseReview caseReview = new CaseReview();
caseReview.setId(IDGenerator.nextStr());
caseReview.setName(name);
caseReview.setNum(1001L);
caseReview.setModuleId(a1a1Node.getId());
caseReview.setProjectId(project.getId());
caseReview.setStatus(CaseReviewStatus.PREPARED.toString());

View File

@ -9,10 +9,22 @@ INSERT INTO template (id, name, remark, internal, update_time, create_time, crea
VALUES ('test_template_case_review_gyq_id', 'functional_case_review_gyq', '', b'0', 1696992836000, 1696992836000, 'admin', 'PROJECT', 'project-gyq-case-review-test', b'0', NULL, 'FUNCTIONAL');
INSERT INTO functional_case(id, num, module_id, project_id, template_id, name, review_status, tags, case_edit_type, pos, version_id, ref_id, last_execute_result, deleted, public_case, latest, create_user, update_user, delete_user, create_time, update_time, delete_time)
VALUES ('CASE_REVIEW_TEST_GYQ_ID', 1, 'CASE_REVIEW_TEST_MODULE_ID', 'project-gyq-case-review-test', '100001', '关联需求测试', 'UN_REVIEWED', NULL, 'STEP', 0, 'v1.0.0', 'CASE_REVIEW_TEST_GYQ_ID', 'UN_EXECUTED', true, b'0', b'0', 'gyq', 'gyq', '', 1698058347559, 1698058347559, NULL);
VALUES ('CASE_REVIEW_TEST_GYQ_ID', 1, 'CASE_REVIEW_TEST_MODULE_ID', 'project-gyq-case-review-test', '100001', '关联需求测试1', 'UN_REVIEWED', NULL, 'STEP', 0, 'v1.0.0', 'CASE_REVIEW_TEST_GYQ_ID', 'UN_EXECUTED', true, b'0', b'0', 'gyq', 'gyq', '', 1698058347559, 1698058347559, NULL);
INSERT INTO functional_case(id, num, module_id, project_id, template_id, name, review_status, tags, case_edit_type, pos, version_id, ref_id, last_execute_result, deleted, public_case, latest, create_user, update_user, delete_user, create_time, update_time, delete_time)
VALUES ('CASE_REVIEW_TEST_GYQ_ID2', 1, 'CASE_REVIEW_TEST_MODULE_ID', 'project-gyq-case-review-test', '100001', '关联需求测试', 'UN_REVIEWED', NULL, 'STEP', 0, 'v1.0.0', 'CASE_REVIEW_TEST_GYQ_ID2', 'UN_EXECUTED', true, b'0', b'0', 'gyq', 'gyq', '', 1698058347559, 1698058347559, NULL);
VALUES ('CASE_REVIEW_TEST_GYQ_ID2', 1, 'CASE_REVIEW_TEST_MODULE_ID', 'project-gyq-case-review-test', '100001', '关联需求测试2', 'UN_REVIEWED', NULL, 'STEP', 0, 'v1.0.0', 'CASE_REVIEW_TEST_GYQ_ID2', 'UN_EXECUTED', true, b'0', b'0', 'gyq', 'gyq', '', 1698058347559, 1698058347559, NULL);
INSERT INTO functional_case(id, num, module_id, project_id, template_id, name, review_status, tags, case_edit_type, pos, version_id, ref_id, last_execute_result, deleted, public_case, latest, create_user, update_user, delete_user, create_time, update_time, delete_time)
VALUES ('CASE_REVIEW_TEST_GYQ_ID3', 1, 'CASE_REVIEW_TEST_MODULE_ID', 'project-gyq-case-review-test', '100001', '关联需求测试3', 'UN_REVIEWED', NULL, 'STEP', 0, 'v1.0.0', 'CASE_REVIEW_TEST_GYQ_ID3', 'UN_EXECUTED', true, b'0', b'0', 'gyq', 'gyq', '', 1698058347559, 1698058347559, NULL);
INSERT INTO functional_case(id, num, module_id, project_id, template_id, name, review_status, tags, case_edit_type, pos, version_id, ref_id, last_execute_result, deleted, public_case, latest, create_user, update_user, delete_user, create_time, update_time, delete_time)
VALUES ('CASE_REVIEW_TEST_GYQ_ID4', 1, 'CASE_REVIEW_TEST_MODULE_ID', 'project-gyq-case-review-test', '100001', '关联需求测试4', 'UN_REVIEWED', NULL, 'STEP', 0, 'v1.0.0', 'CASE_REVIEW_TEST_GYQ_ID4', 'UN_EXECUTED', true, b'0', b'0', 'gyq', 'gyq', '', 1698058347559, 1698058347559, NULL);
INSERT INTO functional_case(id, num, module_id, project_id, template_id, name, review_status, tags, case_edit_type, pos, version_id, ref_id, last_execute_result, deleted, public_case, latest, create_user, update_user, delete_user, create_time, update_time, delete_time)
VALUES ('CASE_REVIEW_TEST_GYQ_ID5', 1, 'CASE_REVIEW_TEST_MODULE_ID', 'project-gyq-case-review-test', '100001', '关联需求测试5', 'UN_REVIEWED', NULL, 'STEP', 0, 'v1.0.0', 'CASE_REVIEW_TEST_GYQ_ID5', 'UN_EXECUTED', true, b'0', b'0', 'gyq', 'gyq', '', 1698058347559, 1698058347559, NULL);
INSERT INTO functional_case(id, num, module_id, project_id, template_id, name, review_status, tags, case_edit_type, pos, version_id, ref_id, last_execute_result, deleted, public_case, latest, create_user, update_user, delete_user, create_time, update_time, delete_time)
VALUES ('CASE_REVIEW_TEST_GYQ_ID6', 1, 'CASE_REVIEW_TEST_MODULE_ID', 'project-gyq-case-review-test', '100001', '关联需求测试6', 'UN_REVIEWED', NULL, 'STEP', 0, 'v1.0.0', 'CASE_REVIEW_TEST_GYQ_ID6', 'UN_EXECUTED', true, b'0', b'0', 'gyq', 'gyq', '', 1698058347559, 1698058347559, NULL);
INSERT INTO functional_case_custom_field(case_id, field_id, value) VALUES ('CASE_REVIEW_TEST_GYQ_ID', 'gyq_custom_id_review1', '22');
INSERT INTO functional_case_custom_field(case_id, field_id, value) VALUES ('CASE_REVIEW_TEST_GYQ_ID', 'gyq_custom_id_review2', '33');

View File

@ -1,5 +1,6 @@
package io.metersphere.system.config.interceptor;
import io.metersphere.functional.domain.CaseReviewFunctionalCaseArchive;
import io.metersphere.functional.domain.FunctionalCaseHistory;
import io.metersphere.sdk.util.CompressUtils;
import io.metersphere.system.utils.MybatisInterceptorConfig;
@ -16,8 +17,7 @@ public class FunctionalCaseInterceptor {
List<MybatisInterceptorConfig> configList = new ArrayList<>();
configList.add(new MybatisInterceptorConfig(FunctionalCaseHistory.class, "content", CompressUtils.class, "zip", "unzip"));
configList.add(new MybatisInterceptorConfig(CaseReviewFunctionalCaseArchive.class, "content", CompressUtils.class, "zip", "unzip"));
return configList;
}
}

View File

@ -65,7 +65,7 @@ public class OperationLogAspect {
// 此方法随时补充类型需要在内容变更前执行的类型都可以加入
private final OperationLogType[] beforeMethodNames = new OperationLogType[]{OperationLogType.UPDATE, OperationLogType.DELETE
, OperationLogType.RECOVER, OperationLogType.DISASSOCIATE, OperationLogType.ARCHIVED};
, OperationLogType.RECOVER, OperationLogType.DISASSOCIATE,OperationLogType.ASSOCIATE, OperationLogType.ARCHIVED};
// 需要后置执行合并内容的
private final OperationLogType[] postMethodNames = new OperationLogType[]{OperationLogType.ADD, OperationLogType.UPDATE};

View File

@ -17,6 +17,7 @@ public enum OperationLogType {
RECOVER,
LOGOUT,
DISASSOCIATE,
ASSOCIATE,
ARCHIVED;
public boolean contains(OperationLogType keyword) {

View File

@ -43,6 +43,7 @@ VALUES ('aspect_gyq_api_scenario_one', 'api_scenario', 'p1', 'test-api-status',
INSERT INTO test_plan(id, project_id, parent_id, name, status, stage, tags, create_time, create_user, update_time, update_user, planned_start_time, planned_end_time, actual_start_time, actual_end_time, description)
VALUES ('aspect_gyq_test_plan_one','100001100001', 'NONE', 'test_plan', 'test-api-status', 'Smock', null, UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 2000, UNIX_TIMESTAMP() * 3000 ,UNIX_TIMESTAMP() * 2000, UNIX_TIMESTAMP() * 3000,null);
INSERT INTO case_review(id, name, module_id, project_id, start_time, end_time, tags, description, create_time, create_user, update_time, update_user)
VALUES ('aspect_gyq_case_review_one','case_review','module_id', '100001100001', null, null, null, null, UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin');
INSERT INTO case_review(id, num, name, module_id, project_id, status, review_pass_rule, pos, start_time, end_time, tags, description, create_time, create_user, update_time, update_user)
VALUES ('aspect_gyq_case_review_one','10001','case_review','module_id', '100001100001','PREPARED','SINGLE','0', null, null, null, null, UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin');