feat(测试计划): 测试计划基础功能开发

This commit is contained in:
song-tianyang 2024-01-12 13:05:50 +08:00 committed by 建国
parent ab9ffc61ce
commit f227f97679
57 changed files with 2246 additions and 1254 deletions

View File

@ -8,68 +8,167 @@ import jakarta.validation.constraints.Size;
import lombok.Data;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Data
public class TestPlan implements Serializable {
@Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan.id.not_blank}", groups = {Updated.class})
@Size(min = 1, max = 50, message = "{test_plan.id.length_range}", groups = {Created.class, Updated.class})
private String id;
@Schema(description = "测试计划所属项目", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "num")
private Long num;
@Schema(description = "测试计划所属项目", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan.project_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{test_plan.project_id.length_range}", groups = {Created.class, Updated.class})
private String projectId;
@Schema(description = "测试计划父ID;测试计划要改为树结构。最上层的为root其余则是父节点ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan.parent_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{test_plan.parent_id.length_range}", groups = {Created.class, Updated.class})
private String parentId;
@Schema(description = "测试计划组ID;默认为none.只关联type为group的测试计划", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan.group_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{test_plan.group_id.length_range}", groups = {Created.class, Updated.class})
private String groupId;
@Schema(description = "测试计划名称", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "测试计划模块ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan.module_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{test_plan.module_id.length_range}", groups = {Created.class, Updated.class})
private String moduleId;
@Schema(description = "测试计划名称", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan.name.not_blank}", groups = {Created.class})
@Size(min = 1, max = 255, message = "{test_plan.name.length_range}", groups = {Created.class, Updated.class})
private String name;
@Schema(description = "测试计划状态;进行中/未开始/已完成/已结束/已归档", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "测试计划状态;未开始,进行中,已完成,已归档", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan.status.not_blank}", groups = {Created.class})
@Size(min = 1, max = 20, message = "{test_plan.status.length_range}", groups = {Created.class, Updated.class})
private String status;
@Schema(description = "测试阶段", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan.stage.not_blank}", groups = {Created.class})
@Size(min = 1, max = 30, message = "{test_plan.stage.length_range}", groups = {Created.class, Updated.class})
private String stage;
@Schema(description = "数据类型;测试计划组group/测试计划testPlan", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan.type.not_blank}", groups = {Created.class})
@Size(min = 1, max = 30, message = "{test_plan.type.length_range}", groups = {Created.class, Updated.class})
private String type;
@Schema(description = "标签")
private String tags;
@Schema(description = "标签")
private List<String> tags;
@Schema(description = "创建时间")
@Schema(description = "创建时间")
private Long createTime;
@Schema(description = "创建人")
@Schema(description = "创建人")
private String createUser;
@Schema(description = "更新时间")
@Schema(description = "更新时间")
private Long updateTime;
@Schema(description = "更新人")
@Schema(description = "更新人")
private String updateUser;
@Schema(description = "计划开始时间")
@Schema(description = "计划开始时间")
private Long plannedStartTime;
@Schema(description = "计划结束时间")
@Schema(description = "计划结束时间")
private Long plannedEndTime;
@Schema(description = "实际开始时间")
@Schema(description = "实际开始时间")
private Long actualStartTime;
@Schema(description = "实际结束时间")
@Schema(description = "实际结束时间")
private Long actualEndTime;
@Schema(description = "描述")
@Schema(description = "描述;描述")
private String description;
private static final long serialVersionUID = 1L;
public enum Column {
id("id", "id", "VARCHAR", false),
num("num", "num", "BIGINT", false),
projectId("project_id", "projectId", "VARCHAR", false),
groupId("group_id", "groupId", "VARCHAR", false),
moduleId("module_id", "moduleId", "VARCHAR", false),
name("name", "name", "VARCHAR", true),
status("status", "status", "VARCHAR", true),
type("type", "type", "VARCHAR", true),
tags("tags", "tags", "VARCHAR", false),
createTime("create_time", "createTime", "BIGINT", false),
createUser("create_user", "createUser", "VARCHAR", false),
updateTime("update_time", "updateTime", "BIGINT", false),
updateUser("update_user", "updateUser", "VARCHAR", false),
plannedStartTime("planned_start_time", "plannedStartTime", "BIGINT", false),
plannedEndTime("planned_end_time", "plannedEndTime", "BIGINT", false),
actualStartTime("actual_start_time", "actualStartTime", "BIGINT", false),
actualEndTime("actual_end_time", "actualEndTime", "BIGINT", false),
description("description", "description", "VARCHAR", false);
private static final String BEGINNING_DELIMITER = "`";
private static final String ENDING_DELIMITER = "`";
private final String column;
private final boolean isColumnNameDelimited;
private final String javaProperty;
private final String jdbcType;
public String value() {
return this.column;
}
public String getValue() {
return this.column;
}
public String getJavaProperty() {
return this.javaProperty;
}
public String getJdbcType() {
return this.jdbcType;
}
Column(String column, String javaProperty, String jdbcType, boolean isColumnNameDelimited) {
this.column = column;
this.javaProperty = javaProperty;
this.jdbcType = jdbcType;
this.isColumnNameDelimited = isColumnNameDelimited;
}
public String desc() {
return this.getEscapedColumnName() + " DESC";
}
public String asc() {
return this.getEscapedColumnName() + " ASC";
}
public static Column[] excludes(Column ... excludes) {
ArrayList<Column> columns = new ArrayList<>(Arrays.asList(Column.values()));
if (excludes != null && excludes.length > 0) {
columns.removeAll(new ArrayList<>(Arrays.asList(excludes)));
}
return columns.toArray(new Column[]{});
}
public static Column[] all() {
return Column.values();
}
public String getEscapedColumnName() {
if (this.isColumnNameDelimited) {
return new StringBuilder().append(BEGINNING_DELIMITER).append(this.column).append(ENDING_DELIMITER).toString();
} else {
return this.column;
}
}
public String getAliasedEscapedColumnName() {
return this.getEscapedColumnName();
}
}
}

View File

@ -1,38 +1,109 @@
package io.metersphere.plan.domain;
import io.metersphere.validation.groups.Created;
import io.metersphere.validation.groups.Updated;
import io.metersphere.validation.groups.*;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
import jakarta.validation.constraints.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import lombok.Data;
@Data
public class TestPlanConfig implements Serializable {
@Schema(description = "测试计划ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan_config.test_plan_id.not_blank}", groups = {Updated.class})
@Schema(description = "测试计划ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan_config.test_plan_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{test_plan_config.test_plan_id.length_range}", groups = {Created.class, Updated.class})
private String testPlanId;
@Schema(description = "是否自定更新功能用例状态", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan_config.automatic_status_update.not_blank}", groups = {Created.class})
@Schema(description = "是否自定更新功能用例状态", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "{test_plan_config.automatic_status_update.not_blank}", groups = {Created.class})
private Boolean automaticStatusUpdate;
@Schema(description = "是否允许重复添加用例", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan_config.repeat_case.not_blank}", groups = {Created.class})
@Schema(description = "是否允许重复添加用例", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "{test_plan_config.repeat_case.not_blank}", groups = {Created.class})
private Boolean repeatCase;
@Schema(description = "测试计划通过阈值;0-100", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "测试计划通过阈值;0-100", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "{test_plan_config.pass_threshold.not_blank}", groups = {Created.class})
private Integer passThreshold;
private Double passThreshold;
@Schema(description = "运行模式", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan_config.run_mode_config.not_blank}", groups = {Created.class})
@Size(min = 1, max = 65535, message = "{test_plan_config.run_mode_config.length_range}", groups = {Created.class, Updated.class})
@Schema(description = "运行模式")
private String runModeConfig;
private static final long serialVersionUID = 1L;
public enum Column {
testPlanId("test_plan_id", "testPlanId", "VARCHAR", false),
automaticStatusUpdate("automatic_status_update", "automaticStatusUpdate", "BIT", false),
repeatCase("repeat_case", "repeatCase", "BIT", false),
passThreshold("pass_threshold", "passThreshold", "DOUBLE", false),
runModeConfig("run_mode_config", "runModeConfig", "LONGVARCHAR", false);
private static final String BEGINNING_DELIMITER = "`";
private static final String ENDING_DELIMITER = "`";
private final String column;
private final boolean isColumnNameDelimited;
private final String javaProperty;
private final String jdbcType;
public String value() {
return this.column;
}
public String getValue() {
return this.column;
}
public String getJavaProperty() {
return this.javaProperty;
}
public String getJdbcType() {
return this.jdbcType;
}
Column(String column, String javaProperty, String jdbcType, boolean isColumnNameDelimited) {
this.column = column;
this.javaProperty = javaProperty;
this.jdbcType = jdbcType;
this.isColumnNameDelimited = isColumnNameDelimited;
}
public String desc() {
return this.getEscapedColumnName() + " DESC";
}
public String asc() {
return this.getEscapedColumnName() + " ASC";
}
public static Column[] excludes(Column ... excludes) {
ArrayList<Column> columns = new ArrayList<>(Arrays.asList(Column.values()));
if (excludes != null && excludes.length > 0) {
columns.removeAll(new ArrayList<>(Arrays.asList(excludes)));
}
return columns.toArray(new Column[]{});
}
public static Column[] all() {
return Column.values();
}
public String getEscapedColumnName() {
if (this.isColumnNameDelimited) {
return new StringBuilder().append(BEGINNING_DELIMITER).append(this.column).append(ENDING_DELIMITER).toString();
} else {
return this.column;
}
}
public String getAliasedEscapedColumnName() {
return this.getEscapedColumnName();
}
}
}

View File

@ -304,52 +304,52 @@ public class TestPlanConfigExample {
return (Criteria) this;
}
public Criteria andPassThresholdEqualTo(Integer value) {
public Criteria andPassThresholdEqualTo(Double value) {
addCriterion("pass_threshold =", value, "passThreshold");
return (Criteria) this;
}
public Criteria andPassThresholdNotEqualTo(Integer value) {
public Criteria andPassThresholdNotEqualTo(Double value) {
addCriterion("pass_threshold <>", value, "passThreshold");
return (Criteria) this;
}
public Criteria andPassThresholdGreaterThan(Integer value) {
public Criteria andPassThresholdGreaterThan(Double value) {
addCriterion("pass_threshold >", value, "passThreshold");
return (Criteria) this;
}
public Criteria andPassThresholdGreaterThanOrEqualTo(Integer value) {
public Criteria andPassThresholdGreaterThanOrEqualTo(Double value) {
addCriterion("pass_threshold >=", value, "passThreshold");
return (Criteria) this;
}
public Criteria andPassThresholdLessThan(Integer value) {
public Criteria andPassThresholdLessThan(Double value) {
addCriterion("pass_threshold <", value, "passThreshold");
return (Criteria) this;
}
public Criteria andPassThresholdLessThanOrEqualTo(Integer value) {
public Criteria andPassThresholdLessThanOrEqualTo(Double value) {
addCriterion("pass_threshold <=", value, "passThreshold");
return (Criteria) this;
}
public Criteria andPassThresholdIn(List<Integer> values) {
public Criteria andPassThresholdIn(List<Double> values) {
addCriterion("pass_threshold in", values, "passThreshold");
return (Criteria) this;
}
public Criteria andPassThresholdNotIn(List<Integer> values) {
public Criteria andPassThresholdNotIn(List<Double> values) {
addCriterion("pass_threshold not in", values, "passThreshold");
return (Criteria) this;
}
public Criteria andPassThresholdBetween(Integer value1, Integer value2) {
public Criteria andPassThresholdBetween(Double value1, Double value2) {
addCriterion("pass_threshold between", value1, value2, "passThreshold");
return (Criteria) this;
}
public Criteria andPassThresholdNotBetween(Integer value1, Integer value2) {
public Criteria andPassThresholdNotBetween(Double value1, Double value2) {
addCriterion("pass_threshold not between", value1, value2, "passThreshold");
return (Criteria) this;
}

View File

@ -64,19 +64,50 @@ public class TestPlanExample {
}
protected abstract static class GeneratedCriteria {
protected List<Criterion> tagsCriteria;
protected List<Criterion> allCriteria;
protected List<Criterion> criteria;
protected GeneratedCriteria() {
super();
criteria = new ArrayList<Criterion>();
tagsCriteria = new ArrayList<Criterion>();
}
public List<Criterion> getTagsCriteria() {
return tagsCriteria;
}
protected void addTagsCriterion(String condition, Object value, String property) {
if (value == null) {
throw new RuntimeException("Value for " + property + " cannot be null");
}
tagsCriteria.add(new Criterion(condition, value, "io.metersphere.handler.ListTypeHandler"));
allCriteria = null;
}
protected void addTagsCriterion(String condition, List<String> value1, List<String> value2, String property) {
if (value1 == null || value2 == null) {
throw new RuntimeException("Between values for " + property + " cannot be null");
}
tagsCriteria.add(new Criterion(condition, value1, value2, "io.metersphere.handler.ListTypeHandler"));
allCriteria = null;
}
public boolean isValid() {
return criteria.size() > 0;
return criteria.size() > 0
|| tagsCriteria.size() > 0;
}
public List<Criterion> getAllCriteria() {
return criteria;
if (allCriteria == null) {
allCriteria = new ArrayList<Criterion>();
allCriteria.addAll(criteria);
allCriteria.addAll(tagsCriteria);
}
return allCriteria;
}
public List<Criterion> getCriteria() {
@ -88,6 +119,7 @@ public class TestPlanExample {
throw new RuntimeException("Value for condition cannot be null");
}
criteria.add(new Criterion(condition));
allCriteria = null;
}
protected void addCriterion(String condition, Object value, String property) {
@ -95,6 +127,7 @@ public class TestPlanExample {
throw new RuntimeException("Value for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value));
allCriteria = null;
}
protected void addCriterion(String condition, Object value1, Object value2, String property) {
@ -102,6 +135,7 @@ public class TestPlanExample {
throw new RuntimeException("Between values for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value1, value2));
allCriteria = null;
}
public Criteria andIdIsNull() {
@ -174,6 +208,66 @@ public class TestPlanExample {
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 andProjectIdIsNull() {
addCriterion("project_id is null");
return (Criteria) this;
@ -244,73 +338,143 @@ public class TestPlanExample {
return (Criteria) this;
}
public Criteria andParentIdIsNull() {
addCriterion("parent_id is null");
public Criteria andGroupIdIsNull() {
addCriterion("group_id is null");
return (Criteria) this;
}
public Criteria andParentIdIsNotNull() {
addCriterion("parent_id is not null");
public Criteria andGroupIdIsNotNull() {
addCriterion("group_id is not null");
return (Criteria) this;
}
public Criteria andParentIdEqualTo(String value) {
addCriterion("parent_id =", value, "parentId");
public Criteria andGroupIdEqualTo(String value) {
addCriterion("group_id =", value, "groupId");
return (Criteria) this;
}
public Criteria andParentIdNotEqualTo(String value) {
addCriterion("parent_id <>", value, "parentId");
public Criteria andGroupIdNotEqualTo(String value) {
addCriterion("group_id <>", value, "groupId");
return (Criteria) this;
}
public Criteria andParentIdGreaterThan(String value) {
addCriterion("parent_id >", value, "parentId");
public Criteria andGroupIdGreaterThan(String value) {
addCriterion("group_id >", value, "groupId");
return (Criteria) this;
}
public Criteria andParentIdGreaterThanOrEqualTo(String value) {
addCriterion("parent_id >=", value, "parentId");
public Criteria andGroupIdGreaterThanOrEqualTo(String value) {
addCriterion("group_id >=", value, "groupId");
return (Criteria) this;
}
public Criteria andParentIdLessThan(String value) {
addCriterion("parent_id <", value, "parentId");
public Criteria andGroupIdLessThan(String value) {
addCriterion("group_id <", value, "groupId");
return (Criteria) this;
}
public Criteria andParentIdLessThanOrEqualTo(String value) {
addCriterion("parent_id <=", value, "parentId");
public Criteria andGroupIdLessThanOrEqualTo(String value) {
addCriterion("group_id <=", value, "groupId");
return (Criteria) this;
}
public Criteria andParentIdLike(String value) {
addCriterion("parent_id like", value, "parentId");
public Criteria andGroupIdLike(String value) {
addCriterion("group_id like", value, "groupId");
return (Criteria) this;
}
public Criteria andParentIdNotLike(String value) {
addCriterion("parent_id not like", value, "parentId");
public Criteria andGroupIdNotLike(String value) {
addCriterion("group_id not like", value, "groupId");
return (Criteria) this;
}
public Criteria andParentIdIn(List<String> values) {
addCriterion("parent_id in", values, "parentId");
public Criteria andGroupIdIn(List<String> values) {
addCriterion("group_id in", values, "groupId");
return (Criteria) this;
}
public Criteria andParentIdNotIn(List<String> values) {
addCriterion("parent_id not in", values, "parentId");
public Criteria andGroupIdNotIn(List<String> values) {
addCriterion("group_id not in", values, "groupId");
return (Criteria) this;
}
public Criteria andParentIdBetween(String value1, String value2) {
addCriterion("parent_id between", value1, value2, "parentId");
public Criteria andGroupIdBetween(String value1, String value2) {
addCriterion("group_id between", value1, value2, "groupId");
return (Criteria) this;
}
public Criteria andParentIdNotBetween(String value1, String value2) {
addCriterion("parent_id not between", value1, value2, "parentId");
public Criteria andGroupIdNotBetween(String value1, String value2) {
addCriterion("group_id not between", value1, value2, "groupId");
return (Criteria) this;
}
public Criteria andModuleIdIsNull() {
addCriterion("module_id is null");
return (Criteria) this;
}
public Criteria andModuleIdIsNotNull() {
addCriterion("module_id is not null");
return (Criteria) this;
}
public Criteria andModuleIdEqualTo(String value) {
addCriterion("module_id =", value, "moduleId");
return (Criteria) this;
}
public Criteria andModuleIdNotEqualTo(String value) {
addCriterion("module_id <>", value, "moduleId");
return (Criteria) this;
}
public Criteria andModuleIdGreaterThan(String value) {
addCriterion("module_id >", value, "moduleId");
return (Criteria) this;
}
public Criteria andModuleIdGreaterThanOrEqualTo(String value) {
addCriterion("module_id >=", value, "moduleId");
return (Criteria) this;
}
public Criteria andModuleIdLessThan(String value) {
addCriterion("module_id <", value, "moduleId");
return (Criteria) this;
}
public Criteria andModuleIdLessThanOrEqualTo(String value) {
addCriterion("module_id <=", value, "moduleId");
return (Criteria) this;
}
public Criteria andModuleIdLike(String value) {
addCriterion("module_id like", value, "moduleId");
return (Criteria) this;
}
public Criteria andModuleIdNotLike(String value) {
addCriterion("module_id not like", value, "moduleId");
return (Criteria) this;
}
public Criteria andModuleIdIn(List<String> values) {
addCriterion("module_id in", values, "moduleId");
return (Criteria) this;
}
public Criteria andModuleIdNotIn(List<String> values) {
addCriterion("module_id not in", values, "moduleId");
return (Criteria) this;
}
public Criteria andModuleIdBetween(String value1, String value2) {
addCriterion("module_id between", value1, value2, "moduleId");
return (Criteria) this;
}
public Criteria andModuleIdNotBetween(String value1, String value2) {
addCriterion("module_id not between", value1, value2, "moduleId");
return (Criteria) this;
}
@ -454,73 +618,73 @@ public class TestPlanExample {
return (Criteria) this;
}
public Criteria andStageIsNull() {
addCriterion("stage is null");
public Criteria andTypeIsNull() {
addCriterion("`type` is null");
return (Criteria) this;
}
public Criteria andStageIsNotNull() {
addCriterion("stage is not null");
public Criteria andTypeIsNotNull() {
addCriterion("`type` is not null");
return (Criteria) this;
}
public Criteria andStageEqualTo(String value) {
addCriterion("stage =", value, "stage");
public Criteria andTypeEqualTo(String value) {
addCriterion("`type` =", value, "type");
return (Criteria) this;
}
public Criteria andStageNotEqualTo(String value) {
addCriterion("stage <>", value, "stage");
public Criteria andTypeNotEqualTo(String value) {
addCriterion("`type` <>", value, "type");
return (Criteria) this;
}
public Criteria andStageGreaterThan(String value) {
addCriterion("stage >", value, "stage");
public Criteria andTypeGreaterThan(String value) {
addCriterion("`type` >", value, "type");
return (Criteria) this;
}
public Criteria andStageGreaterThanOrEqualTo(String value) {
addCriterion("stage >=", value, "stage");
public Criteria andTypeGreaterThanOrEqualTo(String value) {
addCriterion("`type` >=", value, "type");
return (Criteria) this;
}
public Criteria andStageLessThan(String value) {
addCriterion("stage <", value, "stage");
public Criteria andTypeLessThan(String value) {
addCriterion("`type` <", value, "type");
return (Criteria) this;
}
public Criteria andStageLessThanOrEqualTo(String value) {
addCriterion("stage <=", value, "stage");
public Criteria andTypeLessThanOrEqualTo(String value) {
addCriterion("`type` <=", value, "type");
return (Criteria) this;
}
public Criteria andStageLike(String value) {
addCriterion("stage like", value, "stage");
public Criteria andTypeLike(String value) {
addCriterion("`type` like", value, "type");
return (Criteria) this;
}
public Criteria andStageNotLike(String value) {
addCriterion("stage not like", value, "stage");
public Criteria andTypeNotLike(String value) {
addCriterion("`type` not like", value, "type");
return (Criteria) this;
}
public Criteria andStageIn(List<String> values) {
addCriterion("stage in", values, "stage");
public Criteria andTypeIn(List<String> values) {
addCriterion("`type` in", values, "type");
return (Criteria) this;
}
public Criteria andStageNotIn(List<String> values) {
addCriterion("stage not in", values, "stage");
public Criteria andTypeNotIn(List<String> values) {
addCriterion("`type` not in", values, "type");
return (Criteria) this;
}
public Criteria andStageBetween(String value1, String value2) {
addCriterion("stage between", value1, value2, "stage");
public Criteria andTypeBetween(String value1, String value2) {
addCriterion("`type` between", value1, value2, "type");
return (Criteria) this;
}
public Criteria andStageNotBetween(String value1, String value2) {
addCriterion("stage not between", value1, value2, "stage");
public Criteria andTypeNotBetween(String value1, String value2) {
addCriterion("`type` not between", value1, value2, "type");
return (Criteria) this;
}
@ -534,63 +698,63 @@ public class TestPlanExample {
return (Criteria) this;
}
public Criteria andTagsEqualTo(String value) {
addCriterion("tags =", value, "tags");
public Criteria andTagsEqualTo(List<String> value) {
addTagsCriterion("tags =", value, "tags");
return (Criteria) this;
}
public Criteria andTagsNotEqualTo(String value) {
addCriterion("tags <>", value, "tags");
public Criteria andTagsNotEqualTo(List<String> value) {
addTagsCriterion("tags <>", value, "tags");
return (Criteria) this;
}
public Criteria andTagsGreaterThan(String value) {
addCriterion("tags >", value, "tags");
public Criteria andTagsGreaterThan(List<String> value) {
addTagsCriterion("tags >", value, "tags");
return (Criteria) this;
}
public Criteria andTagsGreaterThanOrEqualTo(String value) {
addCriterion("tags >=", value, "tags");
public Criteria andTagsGreaterThanOrEqualTo(List<String> value) {
addTagsCriterion("tags >=", value, "tags");
return (Criteria) this;
}
public Criteria andTagsLessThan(String value) {
addCriterion("tags <", value, "tags");
public Criteria andTagsLessThan(List<String> value) {
addTagsCriterion("tags <", value, "tags");
return (Criteria) this;
}
public Criteria andTagsLessThanOrEqualTo(String value) {
addCriterion("tags <=", value, "tags");
public Criteria andTagsLessThanOrEqualTo(List<String> value) {
addTagsCriterion("tags <=", value, "tags");
return (Criteria) this;
}
public Criteria andTagsLike(String value) {
addCriterion("tags like", value, "tags");
public Criteria andTagsLike(List<String> value) {
addTagsCriterion("tags like", value, "tags");
return (Criteria) this;
}
public Criteria andTagsNotLike(String value) {
addCriterion("tags not like", value, "tags");
public Criteria andTagsNotLike(List<String> value) {
addTagsCriterion("tags not like", value, "tags");
return (Criteria) this;
}
public Criteria andTagsIn(List<String> values) {
addCriterion("tags in", values, "tags");
public Criteria andTagsIn(List<List<String>> values) {
addTagsCriterion("tags in", values, "tags");
return (Criteria) this;
}
public Criteria andTagsNotIn(List<String> values) {
addCriterion("tags not in", values, "tags");
public Criteria andTagsNotIn(List<List<String>> values) {
addTagsCriterion("tags not in", values, "tags");
return (Criteria) this;
}
public Criteria andTagsBetween(String value1, String value2) {
addCriterion("tags between", value1, value2, "tags");
public Criteria andTagsBetween(List<String> value1, List<String> value2) {
addTagsCriterion("tags between", value1, value2, "tags");
return (Criteria) this;
}
public Criteria andTagsNotBetween(String value1, String value2) {
addCriterion("tags not between", value1, value2, "tags");
public Criteria andTagsNotBetween(List<String> value1, List<String> value2) {
addTagsCriterion("tags not between", value1, value2, "tags");
return (Criteria) this;
}

View File

@ -1,24 +0,0 @@
package io.metersphere.plan.domain;
import io.metersphere.validation.groups.Created;
import io.metersphere.validation.groups.Updated;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import java.io.Serializable;
import lombok.Data;
@Data
public class TestPlanPrincipal implements Serializable {
@Schema(description = "测试计划ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan_principal.test_plan_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{test_plan_principal.test_plan_id.length_range}", groups = {Created.class, Updated.class})
private String testPlanId;
@Schema(description = "用户ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan_principal.user_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{test_plan_principal.user_id.length_range}", groups = {Created.class, Updated.class})
private String userId;
private static final long serialVersionUID = 1L;
}

View File

@ -1,340 +0,0 @@
package io.metersphere.plan.domain;
import java.util.ArrayList;
import java.util.List;
public class TestPlanPrincipalExample {
protected String orderByClause;
protected boolean distinct;
protected List<Criteria> oredCriteria;
public TestPlanPrincipalExample() {
oredCriteria = new ArrayList<Criteria>();
}
public void setOrderByClause(String orderByClause) {
this.orderByClause = orderByClause;
}
public String getOrderByClause() {
return orderByClause;
}
public void setDistinct(boolean distinct) {
this.distinct = distinct;
}
public boolean isDistinct() {
return distinct;
}
public List<Criteria> getOredCriteria() {
return oredCriteria;
}
public void or(Criteria criteria) {
oredCriteria.add(criteria);
}
public Criteria or() {
Criteria criteria = createCriteriaInternal();
oredCriteria.add(criteria);
return criteria;
}
public Criteria createCriteria() {
Criteria criteria = createCriteriaInternal();
if (oredCriteria.size() == 0) {
oredCriteria.add(criteria);
}
return criteria;
}
protected Criteria createCriteriaInternal() {
Criteria criteria = new Criteria();
return criteria;
}
public void clear() {
oredCriteria.clear();
orderByClause = null;
distinct = false;
}
protected abstract static class GeneratedCriteria {
protected List<Criterion> criteria;
protected GeneratedCriteria() {
super();
criteria = new ArrayList<Criterion>();
}
public boolean isValid() {
return criteria.size() > 0;
}
public List<Criterion> getAllCriteria() {
return criteria;
}
public List<Criterion> getCriteria() {
return criteria;
}
protected void addCriterion(String condition) {
if (condition == null) {
throw new RuntimeException("Value for condition cannot be null");
}
criteria.add(new Criterion(condition));
}
protected void addCriterion(String condition, Object value, String property) {
if (value == null) {
throw new RuntimeException("Value for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value));
}
protected void addCriterion(String condition, Object value1, Object value2, String property) {
if (value1 == null || value2 == null) {
throw new RuntimeException("Between values for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value1, value2));
}
public Criteria andTestPlanIdIsNull() {
addCriterion("test_plan_id is null");
return (Criteria) this;
}
public Criteria andTestPlanIdIsNotNull() {
addCriterion("test_plan_id is not null");
return (Criteria) this;
}
public Criteria andTestPlanIdEqualTo(String value) {
addCriterion("test_plan_id =", value, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdNotEqualTo(String value) {
addCriterion("test_plan_id <>", value, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdGreaterThan(String value) {
addCriterion("test_plan_id >", value, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdGreaterThanOrEqualTo(String value) {
addCriterion("test_plan_id >=", value, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdLessThan(String value) {
addCriterion("test_plan_id <", value, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdLessThanOrEqualTo(String value) {
addCriterion("test_plan_id <=", value, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdLike(String value) {
addCriterion("test_plan_id like", value, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdNotLike(String value) {
addCriterion("test_plan_id not like", value, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdIn(List<String> values) {
addCriterion("test_plan_id in", values, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdNotIn(List<String> values) {
addCriterion("test_plan_id not in", values, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdBetween(String value1, String value2) {
addCriterion("test_plan_id between", value1, value2, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdNotBetween(String value1, String value2) {
addCriterion("test_plan_id not between", value1, value2, "testPlanId");
return (Criteria) this;
}
public Criteria andUserIdIsNull() {
addCriterion("user_id is null");
return (Criteria) this;
}
public Criteria andUserIdIsNotNull() {
addCriterion("user_id is not null");
return (Criteria) this;
}
public Criteria andUserIdEqualTo(String value) {
addCriterion("user_id =", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdNotEqualTo(String value) {
addCriterion("user_id <>", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdGreaterThan(String value) {
addCriterion("user_id >", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdGreaterThanOrEqualTo(String value) {
addCriterion("user_id >=", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdLessThan(String value) {
addCriterion("user_id <", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdLessThanOrEqualTo(String value) {
addCriterion("user_id <=", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdLike(String value) {
addCriterion("user_id like", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdNotLike(String value) {
addCriterion("user_id not like", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdIn(List<String> values) {
addCriterion("user_id in", values, "userId");
return (Criteria) this;
}
public Criteria andUserIdNotIn(List<String> values) {
addCriterion("user_id not in", values, "userId");
return (Criteria) this;
}
public Criteria andUserIdBetween(String value1, String value2) {
addCriterion("user_id between", value1, value2, "userId");
return (Criteria) this;
}
public Criteria andUserIdNotBetween(String value1, String value2) {
addCriterion("user_id not between", value1, value2, "userId");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {
protected Criteria() {
super();
}
}
public static class Criterion {
private String condition;
private Object value;
private Object secondValue;
private boolean noValue;
private boolean singleValue;
private boolean betweenValue;
private boolean listValue;
private String typeHandler;
public String getCondition() {
return condition;
}
public Object getValue() {
return value;
}
public Object getSecondValue() {
return secondValue;
}
public boolean isNoValue() {
return noValue;
}
public boolean isSingleValue() {
return singleValue;
}
public boolean isBetweenValue() {
return betweenValue;
}
public boolean isListValue() {
return listValue;
}
public String getTypeHandler() {
return typeHandler;
}
protected Criterion(String condition) {
super();
this.condition = condition;
this.typeHandler = null;
this.noValue = true;
}
protected Criterion(String condition, Object value, String typeHandler) {
super();
this.condition = condition;
this.value = value;
this.typeHandler = typeHandler;
if (value instanceof List<?>) {
this.listValue = true;
} else {
this.singleValue = true;
}
}
protected Criterion(String condition, Object value) {
this(condition, value, null);
}
protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
super();
this.condition = condition;
this.value = value;
this.secondValue = secondValue;
this.typeHandler = typeHandler;
this.betweenValue = true;
}
protected Criterion(String condition, Object value, Object secondValue) {
this(condition, value, secondValue, null);
}
}
}

View File

@ -33,4 +33,8 @@ public interface TestPlanConfigMapper {
int updateByPrimaryKeyWithBLOBs(TestPlanConfig record);
int updateByPrimaryKey(TestPlanConfig record);
int batchInsert(@Param("list") List<TestPlanConfig> list);
int batchInsertSelective(@Param("list") List<TestPlanConfig> list, @Param("selective") TestPlanConfig.Column ... selective);
}

View File

@ -5,7 +5,7 @@
<id column="test_plan_id" jdbcType="VARCHAR" property="testPlanId" />
<result column="automatic_status_update" jdbcType="BIT" property="automaticStatusUpdate" />
<result column="repeat_case" jdbcType="BIT" property="repeatCase" />
<result column="pass_threshold" jdbcType="INTEGER" property="passThreshold" />
<result column="pass_threshold" jdbcType="DOUBLE" property="passThreshold" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.plan.domain.TestPlanConfig">
<result column="run_mode_config" jdbcType="LONGVARCHAR" property="runModeConfig" />
@ -126,7 +126,7 @@
insert into test_plan_config (test_plan_id, automatic_status_update, repeat_case,
pass_threshold, run_mode_config)
values (#{testPlanId,jdbcType=VARCHAR}, #{automaticStatusUpdate,jdbcType=BIT}, #{repeatCase,jdbcType=BIT},
#{passThreshold,jdbcType=INTEGER}, #{runModeConfig,jdbcType=LONGVARCHAR})
#{passThreshold,jdbcType=DOUBLE}, #{runModeConfig,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.plan.domain.TestPlanConfig">
insert into test_plan_config
@ -158,7 +158,7 @@
#{repeatCase,jdbcType=BIT},
</if>
<if test="passThreshold != null">
#{passThreshold,jdbcType=INTEGER},
#{passThreshold,jdbcType=DOUBLE},
</if>
<if test="runModeConfig != null">
#{runModeConfig,jdbcType=LONGVARCHAR},
@ -184,7 +184,7 @@
repeat_case = #{record.repeatCase,jdbcType=BIT},
</if>
<if test="record.passThreshold != null">
pass_threshold = #{record.passThreshold,jdbcType=INTEGER},
pass_threshold = #{record.passThreshold,jdbcType=DOUBLE},
</if>
<if test="record.runModeConfig != null">
run_mode_config = #{record.runModeConfig,jdbcType=LONGVARCHAR},
@ -199,7 +199,7 @@
set test_plan_id = #{record.testPlanId,jdbcType=VARCHAR},
automatic_status_update = #{record.automaticStatusUpdate,jdbcType=BIT},
repeat_case = #{record.repeatCase,jdbcType=BIT},
pass_threshold = #{record.passThreshold,jdbcType=INTEGER},
pass_threshold = #{record.passThreshold,jdbcType=DOUBLE},
run_mode_config = #{record.runModeConfig,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
@ -210,7 +210,7 @@
set test_plan_id = #{record.testPlanId,jdbcType=VARCHAR},
automatic_status_update = #{record.automaticStatusUpdate,jdbcType=BIT},
repeat_case = #{record.repeatCase,jdbcType=BIT},
pass_threshold = #{record.passThreshold,jdbcType=INTEGER}
pass_threshold = #{record.passThreshold,jdbcType=DOUBLE}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -225,7 +225,7 @@
repeat_case = #{repeatCase,jdbcType=BIT},
</if>
<if test="passThreshold != null">
pass_threshold = #{passThreshold,jdbcType=INTEGER},
pass_threshold = #{passThreshold,jdbcType=DOUBLE},
</if>
<if test="runModeConfig != null">
run_mode_config = #{runModeConfig,jdbcType=LONGVARCHAR},
@ -237,7 +237,7 @@
update test_plan_config
set automatic_status_update = #{automaticStatusUpdate,jdbcType=BIT},
repeat_case = #{repeatCase,jdbcType=BIT},
pass_threshold = #{passThreshold,jdbcType=INTEGER},
pass_threshold = #{passThreshold,jdbcType=DOUBLE},
run_mode_config = #{runModeConfig,jdbcType=LONGVARCHAR}
where test_plan_id = #{testPlanId,jdbcType=VARCHAR}
</update>
@ -245,7 +245,47 @@
update test_plan_config
set automatic_status_update = #{automaticStatusUpdate,jdbcType=BIT},
repeat_case = #{repeatCase,jdbcType=BIT},
pass_threshold = #{passThreshold,jdbcType=INTEGER}
pass_threshold = #{passThreshold,jdbcType=DOUBLE}
where test_plan_id = #{testPlanId,jdbcType=VARCHAR}
</update>
<insert id="batchInsert" parameterType="map">
insert into test_plan_config
(test_plan_id, automatic_status_update, repeat_case, pass_threshold, run_mode_config
)
values
<foreach collection="list" item="item" separator=",">
(#{item.testPlanId,jdbcType=VARCHAR}, #{item.automaticStatusUpdate,jdbcType=BIT},
#{item.repeatCase,jdbcType=BIT}, #{item.passThreshold,jdbcType=DOUBLE}, #{item.runModeConfig,jdbcType=LONGVARCHAR}
)
</foreach>
</insert>
<insert id="batchInsertSelective" parameterType="map">
insert into test_plan_config (
<foreach collection="selective" item="column" separator=",">
${column.escapedColumnName}
</foreach>
)
values
<foreach collection="list" item="item" separator=",">
(
<foreach collection="selective" item="column" separator=",">
<if test="'test_plan_id'.toString() == column.value">
#{item.testPlanId,jdbcType=VARCHAR}
</if>
<if test="'automatic_status_update'.toString() == column.value">
#{item.automaticStatusUpdate,jdbcType=BIT}
</if>
<if test="'repeat_case'.toString() == column.value">
#{item.repeatCase,jdbcType=BIT}
</if>
<if test="'pass_threshold'.toString() == column.value">
#{item.passThreshold,jdbcType=DOUBLE}
</if>
<if test="'run_mode_config'.toString() == column.value">
#{item.runModeConfig,jdbcType=LONGVARCHAR}
</if>
</foreach>
)
</foreach>
</insert>
</mapper>

View File

@ -27,4 +27,8 @@ public interface TestPlanMapper {
int updateByPrimaryKeySelective(TestPlan record);
int updateByPrimaryKey(TestPlan record);
int batchInsert(@Param("list") List<TestPlan> list);
int batchInsertSelective(@Param("list") List<TestPlan> list, @Param("selective") TestPlan.Column ... selective);
}

View File

@ -3,12 +3,14 @@
<mapper namespace="io.metersphere.plan.mapper.TestPlanMapper">
<resultMap id="BaseResultMap" type="io.metersphere.plan.domain.TestPlan">
<id column="id" jdbcType="VARCHAR" property="id" />
<result column="num" jdbcType="BIGINT" property="num" />
<result column="project_id" jdbcType="VARCHAR" property="projectId" />
<result column="parent_id" jdbcType="VARCHAR" property="parentId" />
<result column="group_id" jdbcType="VARCHAR" property="groupId" />
<result column="module_id" jdbcType="VARCHAR" property="moduleId" />
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="status" jdbcType="VARCHAR" property="status" />
<result column="stage" jdbcType="VARCHAR" property="stage" />
<result column="tags" jdbcType="VARCHAR" property="tags" />
<result column="type" jdbcType="VARCHAR" property="type" />
<result column="tags" jdbcType="VARCHAR" property="tags" typeHandler="io.metersphere.handler.ListTypeHandler" />
<result column="create_time" jdbcType="BIGINT" property="createTime" />
<result column="create_user" jdbcType="VARCHAR" property="createUser" />
<result column="update_time" jdbcType="BIGINT" property="updateTime" />
@ -43,6 +45,25 @@
</when>
</choose>
</foreach>
<foreach collection="criteria.tagsCriteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value,typeHandler=io.metersphere.handler.ListTypeHandler}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value,typeHandler=io.metersphere.handler.ListTypeHandler} and #{criterion.secondValue,typeHandler=io.metersphere.handler.ListTypeHandler}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem,typeHandler=io.metersphere.handler.ListTypeHandler}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
@ -72,14 +93,33 @@
</when>
</choose>
</foreach>
<foreach collection="criteria.tagsCriteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value,typeHandler=io.metersphere.handler.ListTypeHandler}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value,typeHandler=io.metersphere.handler.ListTypeHandler} and #{criterion.secondValue,typeHandler=io.metersphere.handler.ListTypeHandler}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem,typeHandler=io.metersphere.handler.ListTypeHandler}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Base_Column_List">
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,
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,
actual_end_time, description
</sql>
<select id="selectByExample" parameterType="io.metersphere.plan.domain.TestPlanExample" resultMap="BaseResultMap">
@ -113,18 +153,20 @@
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.plan.domain.TestPlan">
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 (#{id,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{parentId,jdbcType=VARCHAR},
#{name,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR}, #{stage,jdbcType=VARCHAR},
#{tags,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{createUser,jdbcType=VARCHAR},
#{updateTime,jdbcType=BIGINT}, #{updateUser,jdbcType=VARCHAR}, #{plannedStartTime,jdbcType=BIGINT},
#{plannedEndTime,jdbcType=BIGINT}, #{actualStartTime,jdbcType=BIGINT}, #{actualEndTime,jdbcType=BIGINT},
#{description,jdbcType=VARCHAR})
insert into test_plan (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, actual_end_time, description
)
values (#{id,jdbcType=VARCHAR}, #{num,jdbcType=BIGINT}, #{projectId,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},
#{createTime,jdbcType=BIGINT}, #{createUser,jdbcType=VARCHAR}, #{updateTime,jdbcType=BIGINT},
#{updateUser,jdbcType=VARCHAR}, #{plannedStartTime,jdbcType=BIGINT}, #{plannedEndTime,jdbcType=BIGINT},
#{actualStartTime,jdbcType=BIGINT}, #{actualEndTime,jdbcType=BIGINT}, #{description,jdbcType=VARCHAR}
)
</insert>
<insert id="insertSelective" parameterType="io.metersphere.plan.domain.TestPlan">
insert into test_plan
@ -132,11 +174,17 @@
<if test="id != null">
id,
</if>
<if test="num != null">
num,
</if>
<if test="projectId != null">
project_id,
</if>
<if test="parentId != null">
parent_id,
<if test="groupId != null">
group_id,
</if>
<if test="moduleId != null">
module_id,
</if>
<if test="name != null">
`name`,
@ -144,8 +192,8 @@
<if test="status != null">
`status`,
</if>
<if test="stage != null">
stage,
<if test="type != null">
`type`,
</if>
<if test="tags != null">
tags,
@ -182,11 +230,17 @@
<if test="id != null">
#{id,jdbcType=VARCHAR},
</if>
<if test="num != null">
#{num,jdbcType=BIGINT},
</if>
<if test="projectId != null">
#{projectId,jdbcType=VARCHAR},
</if>
<if test="parentId != null">
#{parentId,jdbcType=VARCHAR},
<if test="groupId != null">
#{groupId,jdbcType=VARCHAR},
</if>
<if test="moduleId != null">
#{moduleId,jdbcType=VARCHAR},
</if>
<if test="name != null">
#{name,jdbcType=VARCHAR},
@ -194,11 +248,11 @@
<if test="status != null">
#{status,jdbcType=VARCHAR},
</if>
<if test="stage != null">
#{stage,jdbcType=VARCHAR},
<if test="type != null">
#{type,jdbcType=VARCHAR},
</if>
<if test="tags != null">
#{tags,jdbcType=VARCHAR},
#{tags,jdbcType=VARCHAR,typeHandler=io.metersphere.handler.ListTypeHandler},
</if>
<if test="createTime != null">
#{createTime,jdbcType=BIGINT},
@ -241,11 +295,17 @@
<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.projectId != null">
project_id = #{record.projectId,jdbcType=VARCHAR},
</if>
<if test="record.parentId != null">
parent_id = #{record.parentId,jdbcType=VARCHAR},
<if test="record.groupId != null">
group_id = #{record.groupId,jdbcType=VARCHAR},
</if>
<if test="record.moduleId != null">
module_id = #{record.moduleId,jdbcType=VARCHAR},
</if>
<if test="record.name != null">
`name` = #{record.name,jdbcType=VARCHAR},
@ -253,11 +313,11 @@
<if test="record.status != null">
`status` = #{record.status,jdbcType=VARCHAR},
</if>
<if test="record.stage != null">
stage = #{record.stage,jdbcType=VARCHAR},
<if test="record.type != null">
`type` = #{record.type,jdbcType=VARCHAR},
</if>
<if test="record.tags != null">
tags = #{record.tags,jdbcType=VARCHAR},
tags = #{record.tags,jdbcType=VARCHAR,typeHandler=io.metersphere.handler.ListTypeHandler},
</if>
<if test="record.createTime != null">
create_time = #{record.createTime,jdbcType=BIGINT},
@ -294,12 +354,14 @@
<update id="updateByExample" parameterType="map">
update test_plan
set id = #{record.id,jdbcType=VARCHAR},
num = #{record.num,jdbcType=BIGINT},
project_id = #{record.projectId,jdbcType=VARCHAR},
parent_id = #{record.parentId,jdbcType=VARCHAR},
group_id = #{record.groupId,jdbcType=VARCHAR},
module_id = #{record.moduleId,jdbcType=VARCHAR},
`name` = #{record.name,jdbcType=VARCHAR},
`status` = #{record.status,jdbcType=VARCHAR},
stage = #{record.stage,jdbcType=VARCHAR},
tags = #{record.tags,jdbcType=VARCHAR},
`type` = #{record.type,jdbcType=VARCHAR},
tags = #{record.tags,jdbcType=VARCHAR,typeHandler=io.metersphere.handler.ListTypeHandler},
create_time = #{record.createTime,jdbcType=BIGINT},
create_user = #{record.createUser,jdbcType=VARCHAR},
update_time = #{record.updateTime,jdbcType=BIGINT},
@ -316,11 +378,17 @@
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.plan.domain.TestPlan">
update test_plan
<set>
<if test="num != null">
num = #{num,jdbcType=BIGINT},
</if>
<if test="projectId != null">
project_id = #{projectId,jdbcType=VARCHAR},
</if>
<if test="parentId != null">
parent_id = #{parentId,jdbcType=VARCHAR},
<if test="groupId != null">
group_id = #{groupId,jdbcType=VARCHAR},
</if>
<if test="moduleId != null">
module_id = #{moduleId,jdbcType=VARCHAR},
</if>
<if test="name != null">
`name` = #{name,jdbcType=VARCHAR},
@ -328,11 +396,11 @@
<if test="status != null">
`status` = #{status,jdbcType=VARCHAR},
</if>
<if test="stage != null">
stage = #{stage,jdbcType=VARCHAR},
<if test="type != null">
`type` = #{type,jdbcType=VARCHAR},
</if>
<if test="tags != null">
tags = #{tags,jdbcType=VARCHAR},
tags = #{tags,jdbcType=VARCHAR,typeHandler=io.metersphere.handler.ListTypeHandler},
</if>
<if test="createTime != null">
create_time = #{createTime,jdbcType=BIGINT},
@ -366,12 +434,14 @@
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.plan.domain.TestPlan">
update test_plan
set project_id = #{projectId,jdbcType=VARCHAR},
parent_id = #{parentId,jdbcType=VARCHAR},
set num = #{num,jdbcType=BIGINT},
project_id = #{projectId,jdbcType=VARCHAR},
group_id = #{groupId,jdbcType=VARCHAR},
module_id = #{moduleId,jdbcType=VARCHAR},
`name` = #{name,jdbcType=VARCHAR},
`status` = #{status,jdbcType=VARCHAR},
stage = #{stage,jdbcType=VARCHAR},
tags = #{tags,jdbcType=VARCHAR},
`type` = #{type,jdbcType=VARCHAR},
tags = #{tags,jdbcType=VARCHAR,typeHandler=io.metersphere.handler.ListTypeHandler},
create_time = #{createTime,jdbcType=BIGINT},
create_user = #{createUser,jdbcType=VARCHAR},
update_time = #{updateTime,jdbcType=BIGINT},
@ -383,4 +453,88 @@
description = #{description,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
<insert id="batchInsert" parameterType="map">
insert into test_plan
(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,
actual_end_time, description)
values
<foreach collection="list" item="item" separator=",">
(#{item.id,jdbcType=VARCHAR}, #{item.num,jdbcType=BIGINT}, #{item.projectId,jdbcType=VARCHAR},
#{item.groupId,jdbcType=VARCHAR}, #{item.moduleId,jdbcType=VARCHAR}, #{item.name,jdbcType=VARCHAR},
#{item.status,jdbcType=VARCHAR}, #{item.type,jdbcType=VARCHAR}, #{item.tags,jdbcType=VARCHAR,typeHandler=io.metersphere.handler.ListTypeHandler},
#{item.createTime,jdbcType=BIGINT}, #{item.createUser,jdbcType=VARCHAR}, #{item.updateTime,jdbcType=BIGINT},
#{item.updateUser,jdbcType=VARCHAR}, #{item.plannedStartTime,jdbcType=BIGINT},
#{item.plannedEndTime,jdbcType=BIGINT}, #{item.actualStartTime,jdbcType=BIGINT},
#{item.actualEndTime,jdbcType=BIGINT}, #{item.description,jdbcType=VARCHAR})
</foreach>
</insert>
<insert id="batchInsertSelective" parameterType="map">
insert into test_plan (
<foreach collection="selective" item="column" separator=",">
${column.escapedColumnName}
</foreach>
)
values
<foreach collection="list" item="item" separator=",">
(
<foreach collection="selective" item="column" separator=",">
<if test="'id'.toString() == column.value">
#{item.id,jdbcType=VARCHAR}
</if>
<if test="'num'.toString() == column.value">
#{item.num,jdbcType=BIGINT}
</if>
<if test="'project_id'.toString() == column.value">
#{item.projectId,jdbcType=VARCHAR}
</if>
<if test="'group_id'.toString() == column.value">
#{item.groupId,jdbcType=VARCHAR}
</if>
<if test="'module_id'.toString() == column.value">
#{item.moduleId,jdbcType=VARCHAR}
</if>
<if test="'name'.toString() == column.value">
#{item.name,jdbcType=VARCHAR}
</if>
<if test="'status'.toString() == column.value">
#{item.status,jdbcType=VARCHAR}
</if>
<if test="'type'.toString() == column.value">
#{item.type,jdbcType=VARCHAR}
</if>
<if test="'tags'.toString() == column.value">
#{item.tags,jdbcType=VARCHAR,typeHandler=io.metersphere.handler.ListTypeHandler}
</if>
<if test="'create_time'.toString() == column.value">
#{item.createTime,jdbcType=BIGINT}
</if>
<if test="'create_user'.toString() == column.value">
#{item.createUser,jdbcType=VARCHAR}
</if>
<if test="'update_time'.toString() == column.value">
#{item.updateTime,jdbcType=BIGINT}
</if>
<if test="'update_user'.toString() == column.value">
#{item.updateUser,jdbcType=VARCHAR}
</if>
<if test="'planned_start_time'.toString() == column.value">
#{item.plannedStartTime,jdbcType=BIGINT}
</if>
<if test="'planned_end_time'.toString() == column.value">
#{item.plannedEndTime,jdbcType=BIGINT}
</if>
<if test="'actual_start_time'.toString() == column.value">
#{item.actualStartTime,jdbcType=BIGINT}
</if>
<if test="'actual_end_time'.toString() == column.value">
#{item.actualEndTime,jdbcType=BIGINT}
</if>
<if test="'description'.toString() == column.value">
#{item.description,jdbcType=VARCHAR}
</if>
</foreach>
)
</foreach>
</insert>
</mapper>

View File

@ -1,24 +0,0 @@
package io.metersphere.plan.mapper;
import io.metersphere.plan.domain.TestPlanPrincipal;
import io.metersphere.plan.domain.TestPlanPrincipalExample;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface TestPlanPrincipalMapper {
long countByExample(TestPlanPrincipalExample example);
int deleteByExample(TestPlanPrincipalExample example);
int deleteByPrimaryKey(@Param("testPlanId") String testPlanId, @Param("userId") String userId);
int insert(TestPlanPrincipal record);
int insertSelective(TestPlanPrincipal record);
List<TestPlanPrincipal> selectByExample(TestPlanPrincipalExample example);
int updateByExampleSelective(@Param("record") TestPlanPrincipal record, @Param("example") TestPlanPrincipalExample example);
int updateByExample(@Param("record") TestPlanPrincipal record, @Param("example") TestPlanPrincipalExample example);
}

View File

@ -1,145 +0,0 @@
<?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.plan.mapper.TestPlanPrincipalMapper">
<resultMap id="BaseResultMap" type="io.metersphere.plan.domain.TestPlanPrincipal">
<id column="test_plan_id" jdbcType="VARCHAR" property="testPlanId" />
<id column="user_id" jdbcType="VARCHAR" property="userId" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
<foreach collection="oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Update_By_Example_Where_Clause">
<where>
<foreach collection="example.oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Base_Column_List">
test_plan_id, user_id
</sql>
<select id="selectByExample" parameterType="io.metersphere.plan.domain.TestPlanPrincipalExample" resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
from test_plan_principal
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<delete id="deleteByPrimaryKey" parameterType="map">
delete from test_plan_principal
where test_plan_id = #{testPlanId,jdbcType=VARCHAR}
and user_id = #{userId,jdbcType=VARCHAR}
</delete>
<delete id="deleteByExample" parameterType="io.metersphere.plan.domain.TestPlanPrincipalExample">
delete from test_plan_principal
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.plan.domain.TestPlanPrincipal">
insert into test_plan_principal (test_plan_id, user_id)
values (#{testPlanId,jdbcType=VARCHAR}, #{userId,jdbcType=VARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.plan.domain.TestPlanPrincipal">
insert into test_plan_principal
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="testPlanId != null">
test_plan_id,
</if>
<if test="userId != null">
user_id,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="testPlanId != null">
#{testPlanId,jdbcType=VARCHAR},
</if>
<if test="userId != null">
#{userId,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.plan.domain.TestPlanPrincipalExample" resultType="java.lang.Long">
select count(*) from test_plan_principal
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</select>
<update id="updateByExampleSelective" parameterType="map">
update test_plan_principal
<set>
<if test="record.testPlanId != null">
test_plan_id = #{record.testPlanId,jdbcType=VARCHAR},
</if>
<if test="record.userId != null">
user_id = #{record.userId,jdbcType=VARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExample" parameterType="map">
update test_plan_principal
set test_plan_id = #{record.testPlanId,jdbcType=VARCHAR},
user_id = #{record.userId,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
</mapper>

View File

@ -1,7 +1,7 @@
-- set innodb lock wait timeout
SET SESSION innodb_lock_wait_timeout = 7200;
CREATE TABLE test_plan_module
CREATE TABLE IF NOT EXISTS test_plan_module
(
`id` VARCHAR(50) NOT NULL COMMENT 'ID',
`project_id` VARCHAR(50) NOT NULL COMMENT '项目名称',
@ -24,11 +24,13 @@ CREATE UNIQUE INDEX uq_name_project_parent ON test_plan_module (project_id, name
CREATE TABLE IF NOT EXISTS test_plan
(
`id` VARCHAR(50) NOT NULL COMMENT 'ID',
`num` BIGINT COMMENT 'num',
`project_id` VARCHAR(50) NOT NULL COMMENT '测试计划所属项目',
`parent_id` VARCHAR(50) NOT NULL COMMENT '测试计划父ID;测试计划要改为树结构。最上层的为root其余则是父节点ID',
`group_id` VARCHAR(50) NOT NULL COMMENT '测试计划组ID;默认为none.只关联type为group的测试计划',
`module_id` VARCHAR(50) NOT NULL COMMENT '测试计划模块ID',
`name` VARCHAR(255) NOT NULL COMMENT '测试计划名称',
`status` VARCHAR(20) NOT NULL COMMENT '测试计划状态;进行中/未开始/已完成/已结束/已归档',
`stage` VARCHAR(30) NOT NULL COMMENT '测试阶段',
`status` VARCHAR(20) NOT NULL COMMENT '测试计划状态;未开始,进行中,已完成,已归档',
`type` VARCHAR(30) NOT NULL COMMENT '数据类型;测试计划组group/测试计划testPlan',
`tags` VARCHAR(500) COMMENT '标签',
`create_time` BIGINT NOT NULL COMMENT '创建时间',
`create_user` VARCHAR(50) NOT NULL COMMENT '创建人',
@ -38,16 +40,28 @@ CREATE TABLE IF NOT EXISTS test_plan
`planned_end_time` BIGINT COMMENT '计划结束时间',
`actual_start_time` BIGINT COMMENT '实际开始时间',
`actual_end_time` BIGINT COMMENT '实际结束时间',
`description` VARCHAR(2000) COMMENT '描述',
`description` VARCHAR(2000) COMMENT '描述',
PRIMARY KEY (id)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_general_ci COMMENT = '测试计划';
) COMMENT = '测试计划';
CREATE INDEX idx_parent_id ON test_plan (project_id);
CREATE INDEX idx_group_id ON test_plan (group_id);
CREATE INDEX idx_project_id ON test_plan (project_id);
CREATE INDEX idx_create_user ON test_plan (create_user);
CREATE INDEX idx_status ON test_plan (status);
CREATE UNIQUE INDEX uq_name_project ON test_plan (project_id, name);
CREATE INDEX idx_module_id ON test_plan (module_id);
CREATE TABLE IF NOT EXISTS test_plan_config
(
`test_plan_id` VARCHAR(50) NOT NULL COMMENT '测试计划ID',
`run_mode_config` TEXT COMMENT '运行模式',
`automatic_status_update` BIT NOT NULL DEFAULT 0 COMMENT '是否自定更新功能用例状态',
`repeat_case` BIT NOT NULL DEFAULT 0 COMMENT '是否允许重复添加用例',
`pass_threshold` DOUBLE NOT NULL DEFAULT 100 COMMENT '测试计划通过阈值;0-100',
PRIMARY KEY (test_plan_id)
) COMMENT = '测试计划配置';
-- set innodb lock wait timeout to default
SET SESSION innodb_lock_wait_timeout = DEFAULT;

View File

@ -43,6 +43,8 @@ INSERT INTO user_role_permission (id, role_id, permission_id) VALUES (UUID_SHORT
INSERT INTO user_role_permission (id, role_id, permission_id) VALUES (UUID_SHORT(), 'member', 'SYSTEM_PERSONAL:READ+UPDATE');
INSERT INTO user_role_permission (id, role_id, permission_id)
VALUES (UUID_SHORT(), 'member', 'PROJECT_TEST_PLAN_MODULE:READ');
INSERT INTO user_role_permission (id, role_id, permission_id)
VALUES (UUID_SHORT(), 'member', 'PROJECT_TEST_PLAN:READ');
-- 组织管理员权限
INSERT INTO user_role_permission (id, role_id, permission_id) VALUES (UUID_SHORT(), 'org_admin', 'ORGANIZATION_USER_ROLE:READ');
@ -196,6 +198,14 @@ INSERT INTO user_role_permission (id, role_id, permission_id)
VALUES (UUID_SHORT(), 'project_admin', 'PROJECT_TEST_PLAN_MODULE:READ+UPDATE');
INSERT INTO user_role_permission (id, role_id, permission_id)
VALUES (UUID_SHORT(), 'project_admin', 'PROJECT_TEST_PLAN_MODULE:READ+DELETE');
INSERT INTO user_role_permission (id, role_id, permission_id)
VALUES (UUID_SHORT(), 'project_admin', 'PROJECT_TEST_PLAN:READ+ADD');
INSERT INTO user_role_permission (id, role_id, permission_id)
VALUES (UUID_SHORT(), 'project_admin', 'PROJECT_TEST_PLAN:READ+UPDATE');
INSERT INTO user_role_permission (id, role_id, permission_id)
VALUES (UUID_SHORT(), 'project_admin', 'PROJECT_TEST_PLAN:READ+DELETE');
INSERT INTO user_role_permission (id, role_id, permission_id)
VALUES (UUID_SHORT(), 'project_admin', 'PROJECT_TEST_PLAN:READ+EXECUTE');
-- 项目成员权限
INSERT INTO user_role_permission (id, role_id, permission_id) VALUES (UUID_SHORT(), 'project_member', 'PROJECT_BASE_INFO:READ');
@ -306,6 +316,14 @@ INSERT INTO user_role_permission (id, role_id, permission_id)
VALUES (UUID_SHORT(), 'project_member', 'PROJECT_TEST_PLAN_MODULE:READ+UPDATE');
INSERT INTO user_role_permission (id, role_id, permission_id)
VALUES (UUID_SHORT(), 'project_member', 'PROJECT_TEST_PLAN_MODULE:READ+DELETE');
INSERT INTO user_role_permission (id, role_id, permission_id)
VALUES (UUID_SHORT(), 'project_member', 'PROJECT_TEST_PLAN:READ+ADD');
INSERT INTO user_role_permission (id, role_id, permission_id)
VALUES (UUID_SHORT(), 'project_member', 'PROJECT_TEST_PLAN:READ+UPDATE');
INSERT INTO user_role_permission (id, role_id, permission_id)
VALUES (UUID_SHORT(), 'project_member', 'PROJECT_TEST_PLAN:READ+DELETE');
INSERT INTO user_role_permission (id, role_id, permission_id)
VALUES (UUID_SHORT(), 'project_member', 'PROJECT_TEST_PLAN:READ+EXECUTE');
-- 初始化当前站点配置
INSERT into system_parameter values('base.url', 'http://127.0.0.1:8081', 'text');
-- 初始化prometheus站点配置

View File

@ -0,0 +1,9 @@
package io.metersphere.sdk.constants;
/**
* 功能用例执行状态
*/
public enum FunctionCaseExecuteStatus {
//未开始成功失败阻塞
PENDING, SUCCESS, ERROR, BLOCK
}

View File

@ -19,4 +19,9 @@ public class ModuleConstants {
public static final String NODE_TYPE_GITLAB = "Gitlab";
public static final String NODE_PROTOCOL_HTTP = "HTTP";
/* 模块数量统计相关key */
public static final String MODULE_COUNT_ALL = "all";
public static final String MODULE_COUNT_MY = "my";
/* 模块数量统计相关key end*/
}

View File

@ -0,0 +1,21 @@
package io.metersphere.sdk.constants;
public class TestPlanConstants {
//测试计划类型-测试计划
public static final String TEST_PLAN_TYPE_PLAN = "TEST_PLAN";
//测试计划类型-测试计划组
public static final String TEST_PLAN_TYPE_GROUP = "GROUP";
//测试计划组默认ID
public static final String TEST_PLAN_DEFAULT_GROUP_ID = "none";
//测试计划状态-未开始
public static final String TEST_PLAN_STATUS_PREPARED = "PREPARED";
//测试计划状态-进行中
public static final String TEST_PLAN_STATUS_UNDERWAY = "UNDERWAY";
//测试计划状态-已完成
public static final String TEST_PLAN_STATUS_COMPLETED = "COMPLETED";
//测试计划状态-已归档
public static final String TEST_PLAN_STATUS_ARCHIVED = "ARCHIVED";
}

View File

@ -71,7 +71,7 @@ public class MinioRepository implements FileRepository {
private String getPath(FileRequest request) {
String folder = request.getFolder();
if (!StringUtils.startsWithAny(folder, "system", "project", "organization")) {
throw new MSException("file.folder.error");
throw new MSException("folder.error");
}
return StringUtils.join(folder, "/", request.getFileName());
}

View File

@ -1,75 +1,82 @@
test_plan.id.not_blank=
test_plan.project_id.length_range=
test_plan.project_id.not_blank=
test_plan.parent_id.length_range=
test_plan.parent_id.not_blank=
test_plan.name.length_range=
test_plan.name.not_blank=
test_plan.status.length_range=
test_plan.status.not_blank=
test_plan.stage.length_range=
test_plan.stage.not_blank=
test_plan.create_user.length_range=
test_plan.create_user.not_blank=
test_plan_report.id.not_blank=
test_plan_report.test_plan_id.length_range=
test_plan_report.test_plan_id.not_blank=
test_plan_report.name.length_range=
test_plan_report.name.not_blank=
test_plan_report.create_user.length_range=
test_plan_report.create_user.not_blank=
test_plan_ui_scenario.id.not_blank=
test_plan_ui_scenario.test_plan_id.length_range=
test_plan_ui_scenario.test_plan_id.not_blank=
test_plan_ui_scenario.ui_scenario_id.length_range=
test_plan_ui_scenario.ui_scenario_id.not_blank=
test_plan_ui_scenario.create_user.length_range=
test_plan_ui_scenario.create_user.not_blank=
test_plan_function_case.id.not_blank=
test_plan_function_case.plan_id.length_range=
test_plan_function_case.plan_id.not_blank=
test_plan_function_case.function_case_id.length_range=
test_plan_function_case.function_case_id.not_blank=
test_plan_function_case.create_user.length_range=
test_plan_function_case.create_user.not_blank=
test_plan_api_scenario.id.not_blank=
test_plan_api_scenario.test_plan_id.length_range=
test_plan_api_scenario.test_plan_id.not_blank=
test_plan_api_scenario.create_user.length_range=
test_plan_api_scenario.create_user.not_blank=
test_plan_follow.test_plan_id.not_blank=
test_plan_follow.user_id.not_blank=
test_plan_api_case.id.not_blank=
test_plan_api_case.test_plan_id.length_range=
test_plan_api_case.test_plan_id.not_blank=
test_plan_api_case.api_case_id.length_range=
test_plan_api_case.api_case_id.not_blank=
test_plan_api_case.create_user.length_range=
test_plan_api_case.create_user.not_blank=
test_plan_config.test_plan_id.not_blank=
test_plan_config.automatic_status_update.length_range=
test_plan_config.automatic_status_update.not_blank=
test_plan_config.repeat_case.length_range=
test_plan_config.repeat_case.not_blank=
test_plan_config.pass_threshold.length_range=
test_plan_config.pass_threshold.not_blank=
test_plan_load_case.id.not_blank=
test_plan_load_case.test_plan_id.length_range=
test_plan_load_case.test_plan_id.not_blank=
test_plan_load_case.load_case_id.length_range=
test_plan_load_case.load_case_id.not_blank=
test_plan_load_case.create_user.length_range=
test_plan_load_case.create_user.not_blank=
test_plan_execute_record_blob.test_plan_execute_record.not_blank=
test_plan_execute_record.id.not_blank=
test_plan_execute_record.test_plan_id.length_range=
test_plan_execute_record.test_plan_id.not_blank=
test_plan_execute_record.name.length_range=
test_plan_execute_record.name.not_blank=
test_plan_execute_record.status.length_range=
test_plan_execute_record.status.not_blank=
test_plan_principal.test_plan_id.not_blank=
test_plan_principal.user_id.not_blank=
test_plan_report_content.id.not_blank=
test_plan_report_content.test_plan_report_id.length_range=
test_plan_report_content.test_plan_report_id.not_blank=
test_plan.id.not_blank=测试计划id不能为空
test_plan.project_id.length_range=测试计划所属项目id长度过长
test_plan.project_id.not_blank=测试计划所属项目id不能为空
test_plan.module_id.not_blank=测试计划模块ID不能为空
test_plan.parent_id.length_range=测试计划父id长度过长
test_plan.parent_id.not_blank=测试计划父id不能为空
test_plan.name.length_range=测试计划名称长度过长
test_plan.name.not_blank=测试计划名称不能为空
test_plan.name.exist=测试计划名称已存在
test_plan.too_many=测试计划数量不能超过{0}个
test_plan.status.length_range=测试计划状态长度过长
test_plan.status.not_blank=测试计划状态不能为空
test_plan.stage.length_range=测试计划阶段长度过长
test_plan.stage.not_blank=测试计划阶段不能为空
test_plan.create_user.length_range=测试计划创建人长度过长
test_plan.create_user.not_blank=测试计划创建人不能为空
test_plan_report.id.not_blank=测试计划报告id不能为空
test_plan_report.test_plan_id.length_range=测试计划id长度过长
test_plan_report.test_plan_id.not_blank=测试计划id不能为空
test_plan_report.name.length_range=测试计划报告名称长度过长
test_plan_report.name.not_blank=测试计划报告名称不能为空
test_plan_report.create_user.length_range=测试计划报告创建人长度过长
test_plan_report.create_user.not_blank=测试计划报告创建人不能为空
test_plan_ui_scenario.id.not_blank=测试计划ui用例id不能为空
test_plan_ui_scenario.test_plan_id.length_range=测试计划ui用例的测试计划id长度过长
test_plan_ui_scenario.test_plan_id.not_blank=测试计划ui用例的测试计划id不能为空
test_plan_ui_scenario.ui_scenario_id.length_range=测试计划ui用例的ui用例id长度过长
test_plan_ui_scenario.ui_scenario_id.not_blank=测试计划ui用例的ui用例id不能为空
test_plan_ui_scenario.create_user.length_range=测试计划ui用例创建人长度过长
test_plan_ui_scenario.create_user.not_blank=测试计划ui用例创建人不能为空
test_plan_function_case.id.not_blank=测试计划功能用例id不能为空
test_plan_function_case.test_plan_id.length_range=测试计划功能用例的测试计划id长度过长
test_plan_function_case.test_plan_id.not_blank=测试计划功能用例的测试计划id不能为空
test_plan_function_case.function_case_id.length_range=测试计划功能用例的功能用例id长度过长
test_plan_function_case.function_case_id.not_blank=测试计划功能用例的功能用例id不能为空
test_plan_function_case.create_user.length_range=测试计划功能用例创建人长度过长
test_plan_function_case.create_user.not_blank=测试计划功能用例创建人不能为空
test_plan_api_scenario.id.not_blank=测试计划api场景id不能为空
test_plan_api_scenario.test_plan_id.length_range=测试计划id长度过长
test_plan_api_scenario.test_plan_id.not_blank=测试计划id不能为空
test_plan_api_scenario.api_scenario_id.length_range=测试计划api场景的api场景id长度过长
test_plan_api_scenario.api_scenario_id.not_blank=测试计划api场景的api场景id不能为空
test_plan_api_scenario.create_user.length_range=测试计划api场景创建人长度过长
test_plan_api_scenario.create_user.not_blank=测试计划api场景创建人不能为空
test_plan_follow.test_plan_id.not_blan=测试计划id不能为空
test_plan_follow.user_id.not_blank=用户id不能为空
test_plan_api_case.id.not_blank=测试计划api用例id不能为空
test_plan_api_case.test_plan_id.length_range=测试计划api用例的测试计划id长度过长
test_plan_api_case.test_plan_id.not_blank=测试计划api用例的测试计划id不能为空
test_plan_api_case.api_case_id.length_range=测试计划api用例的api用例id长度过长
test_plan_api_case.api_case_id.not_blank=测试计划api用例的api用例id不能为空
test_plan_api_case.create_user.length_range=测试计划api用例创建人长度过长
test_plan_api_case.create_user.not_blank=测试计划api用例创建人不能为空
test_plan_config.test_plan_id.not_blank=测试计划id不能为空
test_plan_config.automatic_status_update.length_range=自动状态更新长度过长
test_plan_config.automatic_status_update.not_blank=自动状态更新不能为空
test_plan_config.repeat_case.length_range=重复用例长度过长
test_plan_config.repeat_case.not_blank=重复用例不能为空
test_plan_config.pass_threshold.length_range=通过阈值长度过长
test_plan_config.pass_threshold.not_blank=通过阈值不能为空
test_plan_load_case.id.not_blank=测试计划性能用例id不能为空
test_plan_load_case.test_plan_id.length_range=测试计划性能用例的测试计划id长度过长
test_plan_load_case.test_plan_id.not_blank=测试计划性能用例的测试计划id不能为空
test_plan_load_case.load_case_id.length_range=测试计划性能用例的性能用例id长度过长
test_plan_load_case.load_case_id.not_blank=测试计划性能用例的性能用例id不能为空
test_plan_load_case.create_user.length_range=测试计划性能用例创建人长度过长
test_plan_load_case.create_user.not_blank=测试计划性能用例创建人不能为空
test_plan_execute_record_blob.test_plan_execute_record.not_blank=测试计划执行记录不能为空
test_plan_execute_record.id.not_blank=测试计划执行记录id不能为空
test_plan_execute_record.test_plan_id.length_range=测试计划id长度过长
test_plan_execute_record.test_plan_id.not_blank=测试计划id不能为空
test_plan_execute_record.name.length_range=测试计划执行记录名称长度过长
test_plan_execute_record.name.not_blank=测试计划执行记录名称不能为空
test_plan_execute_record.status.length_range=测试计划执行记录状态长度过长
test_plan_execute_record.status.not_blank=测试计划执行记录状态不能为空
test_plan_principal.test_plan_id.not_blank=测试计划id不能为空
test_plan_principal.user_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.not_blank=测试计划报告id不能为空
log.delete.test_plan=删除测试计划
log.delete.test_plan_group=删除测试计划组

View File

@ -1,10 +1,13 @@
test_plan.id.not_blank=Test plan id cannot be empty
test_plan.project_id.length_range=Test plan project id length too long
test_plan.project_id.not_blank=Test plan project id cannot be empty
test_plan.module_id.not_blank=Test plan module id cannot be empty
test_plan.parent_id.length_range=Test plan parent id length too long
test_plan.parent_id.not_blank=Test plan parent id cannot be empty
test_plan.name.length_range=Test plan name length too long
test_plan.name.not_blank=Test plan name cannot be empty
test_plan.name.exist=Test plan name exist
test_plan.too_many=Test plan cannot larger than {0}
test_plan.status.length_range=Test plan status length too long
test_plan.status.not_blank=Test plan status cannot be empty
test_plan.stage.length_range=Test plan stage length too long
@ -74,4 +77,6 @@ test_plan_principal.test_plan_id.not_blank=Test plan principal test plan id cann
test_plan_principal.user_id.not_blank=Test plan principal user id cannot be empty
test_plan_report_content.id.not_blank=Test plan report content id cannot be empty
test_plan_report_content.test_plan_report_id.length_range=Test plan report content test plan report id length too long
test_plan_report_content.test_plan_report_id.not_blank=Test plan report content test plan report id cannot be empty
test_plan_report_content.test_plan_report_id.not_blank=Test plan report content test plan report id cannot be empty
log.delete.test_plan=Test plan deleted
log.delete.test_plan_group=Test plan group deleted

View File

@ -1,77 +1,82 @@
test_plan.id.not_blank=\u6D4B\u8BD5\u8BA1\u5212ID\u4E0D\u80FD\u4E3A\u7A7A
test_plan.project_id.length_range=\u6D4B\u8BD5\u8BA1\u5212\u6240\u5C5E\u9879\u76EEID\u957F\u5EA6\u8FC7\u957F
test_plan.project_id.not_blank=\u6D4B\u8BD5\u8BA1\u5212\u6240\u5C5E\u9879\u76EEID\u4E0D\u80FD\u4E3A\u7A7A
test_plan.parent_id.length_range=\u6D4B\u8BD5\u8BA1\u5212\u7236ID\u957F\u5EA6\u8FC7\u957F
test_plan.parent_id.not_blank=\u6D4B\u8BD5\u8BA1\u5212\u7236ID\u4E0D\u80FD\u4E3A\u7A7A
test_plan.name.length_range=\u6D4B\u8BD5\u8BA1\u5212\u540D\u79F0\u957F\u5EA6\u8FC7\u957F
test_plan.name.not_blank=\u6D4B\u8BD5\u8BA1\u5212\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A
test_plan.status.length_range=\u6D4B\u8BD5\u8BA1\u5212\u72B6\u6001\u957F\u5EA6\u8FC7\u957F
test_plan.status.not_blank=\u6D4B\u8BD5\u8BA1\u5212\u72B6\u6001\u4E0D\u80FD\u4E3A\u7A7A
test_plan.stage.length_range=\u6D4B\u8BD5\u8BA1\u5212\u9636\u6BB5\u957F\u5EA6\u8FC7\u957F
test_plan.stage.not_blank=\u6D4B\u8BD5\u8BA1\u5212\u9636\u6BB5\u4E0D\u80FD\u4E3A\u7A7A
test_plan.create_user.length_range=\u6D4B\u8BD5\u8BA1\u5212\u521B\u5EFA\u4EBA\u957F\u5EA6\u8FC7\u957F
test_plan.create_user.not_blank=\u6D4B\u8BD5\u8BA1\u5212\u521B\u5EFA\u4EBA\u4E0D\u80FD\u4E3A\u7A7A
test_plan_report.id.not_blank=\u6D4B\u8BD5\u8BA1\u5212\u62A5\u544AID\u4E0D\u80FD\u4E3A\u7A7A
test_plan_report.test_plan_id.length_range=\u6D4B\u8BD5\u8BA1\u5212ID\u957F\u5EA6\u8FC7\u957F
test_plan_report.test_plan_id.not_blank=\u6D4B\u8BD5\u8BA1\u5212ID\u4E0D\u80FD\u4E3A\u7A7A
test_plan_report.name.length_range=\u6D4B\u8BD5\u8BA1\u5212\u62A5\u544A\u540D\u79F0\u957F\u5EA6\u8FC7\u957F
test_plan_report.name.not_blank=\u6D4B\u8BD5\u8BA1\u5212\u62A5\u544A\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A
test_plan_report.create_user.length_range=\u6D4B\u8BD5\u8BA1\u5212\u62A5\u544A\u521B\u5EFA\u4EBA\u957F\u5EA6\u8FC7\u957F
test_plan_report.create_user.not_blank=\u6D4B\u8BD5\u8BA1\u5212\u62A5\u544A\u521B\u5EFA\u4EBA\u4E0D\u80FD\u4E3A\u7A7A
test_plan_ui_scenario.id.not_blank=\u6D4B\u8BD5\u8BA1\u5212UI\u7528\u4F8BID\u4E0D\u80FD\u4E3A\u7A7A
test_plan_ui_scenario.test_plan_id.length_range=\u6D4B\u8BD5\u8BA1\u5212UI\u7528\u4F8B\u7684\u6D4B\u8BD5\u8BA1\u5212ID\u957F\u5EA6\u8FC7\u957F
test_plan_ui_scenario.test_plan_id.not_blank=\u6D4B\u8BD5\u8BA1\u5212UI\u7528\u4F8B\u7684\u6D4B\u8BD5\u8BA1\u5212ID\u4E0D\u80FD\u4E3A\u7A7A
test_plan_ui_scenario.ui_scenario_id.length_range=\u6D4B\u8BD5\u8BA1\u5212UI\u7528\u4F8B\u7684UI\u7528\u4F8BID\u957F\u5EA6\u8FC7\u957F
test_plan_ui_scenario.ui_scenario_id.not_blank=\u6D4B\u8BD5\u8BA1\u5212UI\u7528\u4F8B\u7684UI\u7528\u4F8BID\u4E0D\u80FD\u4E3A\u7A7A
test_plan_ui_scenario.create_user.length_range=\u6D4B\u8BD5\u8BA1\u5212UI\u7528\u4F8B\u521B\u5EFA\u4EBA\u957F\u5EA6\u8FC7\u957F
test_plan_ui_scenario.create_user.not_blank=\u6D4B\u8BD5\u8BA1\u5212UI\u7528\u4F8B\u521B\u5EFA\u4EBA\u4E0D\u80FD\u4E3A\u7A7A
test_plan_function_case.id.not_blank=\u6D4B\u8BD5\u8BA1\u5212\u529F\u80FD\u7528\u4F8BID\u4E0D\u80FD\u4E3A\u7A7A
test_plan_function_case.test_plan_id.length_range=\u6D4B\u8BD5\u8BA1\u5212\u529F\u80FD\u7528\u4F8B\u7684\u6D4B\u8BD5\u8BA1\u5212ID\u957F\u5EA6\u8FC7\u957F
test_plan_function_case.test_plan_id.not_blank=\u6D4B\u8BD5\u8BA1\u5212\u529F\u80FD\u7528\u4F8B\u7684\u6D4B\u8BD5\u8BA1\u5212ID\u4E0D\u80FD\u4E3A\u7A7A
test_plan_function_case.function_case_id.length_range=\u6D4B\u8BD5\u8BA1\u5212\u529F\u80FD\u7528\u4F8B\u7684\u529F\u80FD\u7528\u4F8BID\u957F\u5EA6\u8FC7\u957F
test_plan_function_case.function_case_id.not_blank=\u6D4B\u8BD5\u8BA1\u5212\u529F\u80FD\u7528\u4F8B\u7684\u529F\u80FD\u7528\u4F8BID\u4E0D\u80FD\u4E3A\u7A7A
test_plan_function_case.create_user.length_range=\u6D4B\u8BD5\u8BA1\u5212\u529F\u80FD\u7528\u4F8B\u521B\u5EFA\u4EBA\u957F\u5EA6\u8FC7\u957F
test_plan_function_case.create_user.not_blank=\u6D4B\u8BD5\u8BA1\u5212\u529F\u80FD\u7528\u4F8B\u521B\u5EFA\u4EBA\u4E0D\u80FD\u4E3A\u7A7A
test_plan_api_scenario.id.not_blank=\u6D4B\u8BD5\u8BA1\u5212API\u573A\u666FID\u4E0D\u80FD\u4E3A\u7A7A
test_plan_api_scenario.test_plan_id.length_range=\u6D4B\u8BD5\u8BA1\u5212ID\u957F\u5EA6\u8FC7\u957F
test_plan_api_scenario.test_plan_id.not_blank=\u6D4B\u8BD5\u8BA1\u5212ID\u4E0D\u80FD\u4E3A\u7A7A
test_plan_api_scenario.api_scenario_id.length_range=\u6D4B\u8BD5\u8BA1\u5212Api\u573A\u666F\u7684Api\u573A\u666FID\u957F\u5EA6\u8FC7\u957F
test_plan_api_scenario.api_scenario_id.not_blank=\u6D4B\u8BD5\u8BA1\u5212Api\u573A\u666F\u7684Api\u573A\u666FID\u4E0D\u80FD\u4E3A\u7A7A
test_plan_api_scenario.create_user.length_range=\u6D4B\u8BD5\u8BA1\u5212API\u573A\u666F\u521B\u5EFA\u4EBA\u957F\u5EA6\u8FC7\u957F
test_plan_api_scenario.create_user.not_blank=\u6D4B\u8BD5\u8BA1\u5212API\u573A\u666F\u521B\u5EFA\u4EBA\u4E0D\u80FD\u4E3A\u7A7A
test_plan_follow.test_plan_id.not_blan=\u6D4B\u8BD5\u8BA1\u5212ID\u4E0D\u80FD\u4E3A\u7A7A
test_plan_follow.user_id.not_blank=\u7528\u6237ID\u4E0D\u80FD\u4E3A\u7A7A
test_plan_api_case.id.not_blank=\u6D4B\u8BD5\u8BA1\u5212API\u7528\u4F8BID\u4E0D\u80FD\u4E3A\u7A7A
test_plan_api_case.test_plan_id.length_range=\u6D4B\u8BD5\u8BA1\u5212API\u7528\u4F8B\u7684\u6D4B\u8BD5\u8BA1\u5212ID\u957F\u5EA6\u8FC7\u957F
test_plan_api_case.test_plan_id.not_blank=\u6D4B\u8BD5\u8BA1\u5212API\u7528\u4F8B\u7684\u6D4B\u8BD5\u8BA1\u5212ID\u4E0D\u80FD\u4E3A\u7A7A
test_plan_api_case.api_case_id.length_range=\u6D4B\u8BD5\u8BA1\u5212API\u7528\u4F8B\u7684API\u7528\u4F8BID\u957F\u5EA6\u8FC7\u957F
test_plan_api_case.api_case_id.not_blank=\u6D4B\u8BD5\u8BA1\u5212API\u7528\u4F8B\u7684API\u7528\u4F8BID\u4E0D\u80FD\u4E3A\u7A7A
test_plan_api_case.create_user.length_range=\u6D4B\u8BD5\u8BA1\u5212API\u7528\u4F8B\u521B\u5EFA\u4EBA\u957F\u5EA6\u8FC7\u957F
test_plan_api_case.create_user.not_blank=\u6D4B\u8BD5\u8BA1\u5212API\u7528\u4F8B\u521B\u5EFA\u4EBA\u4E0D\u80FD\u4E3A\u7A7A
test_plan_config.test_plan_id.not_blank=\u6D4B\u8BD5\u8BA1\u5212ID\u4E0D\u80FD\u4E3A\u7A7A
test_plan_config.automatic_status_update.length_range=\u81EA\u52A8\u72B6\u6001\u66F4\u65B0\u957F\u5EA6\u8FC7\u957F
test_plan_config.automatic_status_update.not_blank=\u81EA\u52A8\u72B6\u6001\u66F4\u65B0\u4E0D\u80FD\u4E3A\u7A7A
test_plan_config.repeat_case.length_range=\u91CD\u590D\u7528\u4F8B\u957F\u5EA6\u8FC7\u957F
test_plan_config.repeat_case.not_blank=\u91CD\u590D\u7528\u4F8B\u4E0D\u80FD\u4E3A\u7A7A
test_plan_config.pass_threshold.length_range=\u901A\u8FC7\u9608\u503C\u957F\u5EA6\u8FC7\u957F
test_plan_config.pass_threshold.not_blank=\u901A\u8FC7\u9608\u503C\u4E0D\u80FD\u4E3A\u7A7A
test_plan_load_case.id.not_blank=\u6D4B\u8BD5\u8BA1\u5212\u6027\u80FD\u7528\u4F8BID\u4E0D\u80FD\u4E3A\u7A7A
test_plan_load_case.test_plan_id.length_range=\u6D4B\u8BD5\u8BA1\u5212\u6027\u80FD\u7528\u4F8B\u7684\u6D4B\u8BD5\u8BA1\u5212ID\u957F\u5EA6\u8FC7\u957F
test_plan_load_case.test_plan_id.not_blank=\u6D4B\u8BD5\u8BA1\u5212\u6027\u80FD\u7528\u4F8B\u7684\u6D4B\u8BD5\u8BA1\u5212ID\u4E0D\u80FD\u4E3A\u7A7A
test_plan_load_case.load_case_id.length_range=\u6D4B\u8BD5\u8BA1\u5212\u6027\u80FD\u7528\u4F8B\u7684\u6027\u80FD\u7528\u4F8BID\u957F\u5EA6\u8FC7\u957F
test_plan_load_case.load_case_id.not_blank=\u6D4B\u8BD5\u8BA1\u5212\u6027\u80FD\u7528\u4F8B\u7684\u6027\u80FD\u7528\u4F8BID\u4E0D\u80FD\u4E3A\u7A7A
test_plan_load_case.create_user.length_range=\u6D4B\u8BD5\u8BA1\u5212\u6027\u80FD\u7528\u4F8B\u521B\u5EFA\u4EBA\u957F\u5EA6\u8FC7\u957F
test_plan_load_case.create_user.not_blank=\u6D4B\u8BD5\u8BA1\u5212\u6027\u80FD\u7528\u4F8B\u521B\u5EFA\u4EBA\u4E0D\u80FD\u4E3A\u7A7A
test_plan_execute_record_blob.test_plan_execute_record.not_blank=\u6D4B\u8BD5\u8BA1\u5212\u6267\u884C\u8BB0\u5F55\u4E0D\u80FD\u4E3A\u7A7A
test_plan_execute_record.id.not_blank=\u6D4B\u8BD5\u8BA1\u5212\u6267\u884C\u8BB0\u5F55ID\u4E0D\u80FD\u4E3A\u7A7A
test_plan_execute_record.test_plan_id.length_range=\u6D4B\u8BD5\u8BA1\u5212ID\u957F\u5EA6\u8FC7\u957F
test_plan_execute_record.test_plan_id.not_blank=\u6D4B\u8BD5\u8BA1\u5212ID\u4E0D\u80FD\u4E3A\u7A7A
test_plan_execute_record.name.length_range=\u6D4B\u8BD5\u8BA1\u5212\u6267\u884C\u8BB0\u5F55\u540D\u79F0\u957F\u5EA6\u8FC7\u957F
test_plan_execute_record.name.not_blank=\u6D4B\u8BD5\u8BA1\u5212\u6267\u884C\u8BB0\u5F55\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A
test_plan_execute_record.status.length_range=\u6D4B\u8BD5\u8BA1\u5212\u6267\u884C\u8BB0\u5F55\u72B6\u6001\u957F\u5EA6\u8FC7\u957F
test_plan_execute_record.status.not_blank=\u6D4B\u8BD5\u8BA1\u5212\u6267\u884C\u8BB0\u5F55\u72B6\u6001\u4E0D\u80FD\u4E3A\u7A7A
test_plan_principal.test_plan_id.not_blank=\u6D4B\u8BD5\u8BA1\u5212ID\u4E0D\u80FD\u4E3A\u7A7A
test_plan_principal.user_id.not_blank=\u7528\u6237ID\u4E0D\u80FD\u4E3A\u7A7A
test_plan_report_content.id.not_blank=\u6D4B\u8BD5\u8BA1\u5212\u62A5\u544A\u5185\u5BB9ID\u4E0D\u80FD\u4E3A\u7A7A
test_plan_report_content.test_plan_report_id.length_range=\u6D4B\u8BD5\u8BA1\u5212\u62A5\u544AID\u957F\u5EA6\u8FC7\u957F
test_plan_report_content.test_plan_report_id.not_blank=\u6D4B\u8BD5\u8BA1\u5212\u62A5\u544AID\u4E0D\u80FD\u4E3A\u7A7A
test_plan.id.not_blank=测试计划id不能为空
test_plan.project_id.length_range=测试计划所属项目id长度过长
test_plan.project_id.not_blank=测试计划所属项目id不能为空
test_plan.module_id.not_blank=测试计划模块ID不能为空
test_plan.parent_id.length_range=测试计划父id长度过长
test_plan.parent_id.not_blank=测试计划父id不能为空
test_plan.name.length_range=测试计划名称长度过长
test_plan.name.not_blank=测试计划名称不能为空
test_plan.name.exist=测试计划名称已存在
test_plan.too_many=测试计划数量不能超过{0}个
test_plan.status.length_range=测试计划状态长度过长
test_plan.status.not_blank=测试计划状态不能为空
test_plan.stage.length_range=测试计划阶段长度过长
test_plan.stage.not_blank=测试计划阶段不能为空
test_plan.create_user.length_range=测试计划创建人长度过长
test_plan.create_user.not_blank=测试计划创建人不能为空
test_plan_report.id.not_blank=测试计划报告id不能为空
test_plan_report.test_plan_id.length_range=测试计划id长度过长
test_plan_report.test_plan_id.not_blank=测试计划id不能为空
test_plan_report.name.length_range=测试计划报告名称长度过长
test_plan_report.name.not_blank=测试计划报告名称不能为空
test_plan_report.create_user.length_range=测试计划报告创建人长度过长
test_plan_report.create_user.not_blank=测试计划报告创建人不能为空
test_plan_ui_scenario.id.not_blank=测试计划ui用例id不能为空
test_plan_ui_scenario.test_plan_id.length_range=测试计划ui用例的测试计划id长度过长
test_plan_ui_scenario.test_plan_id.not_blank=测试计划ui用例的测试计划id不能为空
test_plan_ui_scenario.ui_scenario_id.length_range=测试计划ui用例的ui用例id长度过长
test_plan_ui_scenario.ui_scenario_id.not_blank=测试计划ui用例的ui用例id不能为空
test_plan_ui_scenario.create_user.length_range=测试计划ui用例创建人长度过长
test_plan_ui_scenario.create_user.not_blank=测试计划ui用例创建人不能为空
test_plan_function_case.id.not_blank=测试计划功能用例id不能为空
test_plan_function_case.test_plan_id.length_range=测试计划功能用例的测试计划id长度过长
test_plan_function_case.test_plan_id.not_blank=测试计划功能用例的测试计划id不能为空
test_plan_function_case.function_case_id.length_range=测试计划功能用例的功能用例id长度过长
test_plan_function_case.function_case_id.not_blank=测试计划功能用例的功能用例id不能为空
test_plan_function_case.create_user.length_range=测试计划功能用例创建人长度过长
test_plan_function_case.create_user.not_blank=测试计划功能用例创建人不能为空
test_plan_api_scenario.id.not_blank=测试计划api场景id不能为空
test_plan_api_scenario.test_plan_id.length_range=测试计划id长度过长
test_plan_api_scenario.test_plan_id.not_blank=测试计划id不能为空
test_plan_api_scenario.api_scenario_id.length_range=测试计划api场景的api场景id长度过长
test_plan_api_scenario.api_scenario_id.not_blank=测试计划api场景的api场景id不能为空
test_plan_api_scenario.create_user.length_range=测试计划api场景创建人长度过长
test_plan_api_scenario.create_user.not_blank=测试计划api场景创建人不能为空
test_plan_follow.test_plan_id.not_blan=测试计划id不能为空
test_plan_follow.user_id.not_blank=用户id不能为空
test_plan_api_case.id.not_blank=测试计划api用例id不能为空
test_plan_api_case.test_plan_id.length_range=测试计划api用例的测试计划id长度过长
test_plan_api_case.test_plan_id.not_blank=测试计划api用例的测试计划id不能为空
test_plan_api_case.api_case_id.length_range=测试计划api用例的api用例id长度过长
test_plan_api_case.api_case_id.not_blank=测试计划api用例的api用例id不能为空
test_plan_api_case.create_user.length_range=测试计划api用例创建人长度过长
test_plan_api_case.create_user.not_blank=测试计划api用例创建人不能为空
test_plan_config.test_plan_id.not_blank=测试计划id不能为空
test_plan_config.automatic_status_update.length_range=自动状态更新长度过长
test_plan_config.automatic_status_update.not_blank=自动状态更新不能为空
test_plan_config.repeat_case.length_range=重复用例长度过长
test_plan_config.repeat_case.not_blank=重复用例不能为空
test_plan_config.pass_threshold.length_range=通过阈值长度过长
test_plan_config.pass_threshold.not_blank=通过阈值不能为空
test_plan_load_case.id.not_blank=测试计划性能用例id不能为空
test_plan_load_case.test_plan_id.length_range=测试计划性能用例的测试计划id长度过长
test_plan_load_case.test_plan_id.not_blank=测试计划性能用例的测试计划id不能为空
test_plan_load_case.load_case_id.length_range=测试计划性能用例的性能用例id长度过长
test_plan_load_case.load_case_id.not_blank=测试计划性能用例的性能用例id不能为空
test_plan_load_case.create_user.length_range=测试计划性能用例创建人长度过长
test_plan_load_case.create_user.not_blank=测试计划性能用例创建人不能为空
test_plan_execute_record_blob.test_plan_execute_record.not_blank=测试计划执行记录不能为空
test_plan_execute_record.id.not_blank=测试计划执行记录id不能为空
test_plan_execute_record.test_plan_id.length_range=测试计划id长度过长
test_plan_execute_record.test_plan_id.not_blank=测试计划id不能为空
test_plan_execute_record.name.length_range=测试计划执行记录名称长度过长
test_plan_execute_record.name.not_blank=测试计划执行记录名称不能为空
test_plan_execute_record.status.length_range=测试计划执行记录状态长度过长
test_plan_execute_record.status.not_blank=测试计划执行记录状态不能为空
test_plan_principal.test_plan_id.not_blank=测试计划id不能为空
test_plan_principal.user_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.not_blank=测试计划报告id不能为空
log.delete.test_plan=删除测试计划
log.delete.test_plan_group=删除测试计划组

View File

@ -1,77 +1,82 @@
test_plan.id.not_blank=\u6E2C\u8A66\u8A08\u5283ID\u4E0D\u80FD\u70BA\u7A7A
test_plan.project_id.length_range=\u6E2C\u8A66\u8A08\u5283\u6240\u5C6C\u9805\u76EEID\u9577\u5EA6\u904E\u9577
test_plan.project_id.not_blank=\u6E2C\u8A66\u8A08\u5283\u6240\u5C6C\u9805\u76EEID\u4E0D\u80FD\u70BA\u7A7A
test_plan.parent_id.length_range=\u6E2C\u8A66\u8A08\u5283\u7236ID\u9577\u5EA6\u904E\u9577
test_plan.parent_id.not_blank=\u6E2C\u8A66\u8A08\u5283\u7236ID\u4E0D\u80FD\u70BA\u7A7A
test_plan.name.length_range=\u6E2C\u8A66\u8A08\u5283\u540D\u7A31\u9577\u5EA6\u904E\u9577
test_plan.name.not_blank=\u6E2C\u8A66\u8A08\u5283\u540D\u7A31\u4E0D\u80FD\u70BA\u7A7A
test_plan.status.length_range=\u6E2C\u8A66\u8A08\u5283\u72C0\u614B\u9577\u5EA6\u904E\u9577
test_plan.status.not_blank=\u6E2C\u8A66\u8A08\u5283\u72C0\u614B\u4E0D\u80FD\u70BA\u7A7A
test_plan.stage.length_range=\u6E2C\u8A66\u8A08\u5283\u968E\u6BB5\u9577\u5EA6\u904E\u9577
test_plan.stage.not_blank=\u6E2C\u8A66\u8A08\u5283\u968E\u6BB5\u4E0D\u80FD\u70BA\u7A7A
test_plan.create_user.length_range=\u6E2C\u8A66\u8A08\u5283\u5275\u5EFA\u4EBA\u9577\u5EA6\u904E\u9577
test_plan.create_user.not_blank=\u6E2C\u8A66\u8A08\u5283\u5275\u5EFA\u4EBA\u4E0D\u80FD\u70BA\u7A7A
test_plan_report.id.not_blank=\u6E2C\u8A66\u8A08\u5283\u5831\u544AID\u4E0D\u80FD\u70BA\u7A7A
test_plan_report.test_plan_id.length_range=\u6E2C\u8A66\u8A08\u5283ID\u9577\u5EA6\u904E\u9577
test_plan_report.test_plan_id.not_blank=\u6E2C\u8A66\u8A08\u5283ID\u4E0D\u80FD\u70BA\u7A7A
test_plan_report.name.length_range=\u6E2C\u8A66\u8A08\u5283\u5831\u544A\u540D\u7A31\u9577\u5EA6\u904E\u9577
test_plan_report.name.not_blank=\u6E2C\u8A66\u8A08\u5283\u5831\u544A\u540D\u7A31\u4E0D\u80FD\u70BA\u7A7A
test_plan_report.create_user.length_range=\u6E2C\u8A66\u8A08\u5283\u5831\u544A\u5275\u5EFA\u4EBA\u9577\u5EA6\u904E\u9577
test_plan_report.create_user.not_blank=\u6E2C\u8A66\u8A08\u5283\u5831\u544A\u5275\u5EFA\u4EBA\u4E0D\u80FD\u70BA\u7A7A
test_plan_ui_scenario.id.not_blank=\u6E2C\u8A66\u8A08\u5283UI\u7528\u4F8BID\u4E0D\u80FD\u70BA\u7A7A
test_plan_ui_scenario.test_plan_id.length_range=\u6E2C\u8A66\u8A08\u5283UI\u7528\u4F8B\u7684\u6E2C\u8A66\u8A08\u5283ID\u9577\u5EA6\u904E\u9577
test_plan_ui_scenario.test_plan_id.not_blank=\u6E2C\u8A66\u8A08\u5283UI\u7528\u4F8B\u7684\u6E2C\u8A66\u8A08\u5283ID\u4E0D\u80FD\u70BA\u7A7A
test_plan_ui_scenario.ui_scenario_id.length_range=\u6E2C\u8A66\u8A08\u5283UI\u7528\u4F8B\u7684UI\u7528\u4F8BID\u9577\u5EA6\u904E\u9577
test_plan_ui_scenario.ui_scenario_id.not_blank=\u6E2C\u8A66\u8A08\u5283UI\u7528\u4F8B\u7684UI\u7528\u4F8BID\u4E0D\u80FD\u70BA\u7A7A
test_plan_ui_scenario.create_user.length_range=\u6E2C\u8A66\u8A08\u5283UI\u7528\u4F8B\u5275\u5EFA\u4EBA\u9577\u5EA6\u904E\u9577
test_plan_ui_scenario.create_user.not_blank=\u6E2C\u8A66\u8A08\u5283UI\u7528\u4F8B\u5275\u5EFA\u4EBA\u4E0D\u80FD\u70BA\u7A7A
test_plan_function_case.id.not_blank=\u6E2C\u8A66\u8A08\u5283\u529F\u80FD\u7528\u4F8BID\u4E0D\u80FD\u70BA\u7A7A
test_plan_function_case.test_plan_id.length_range=\u6E2C\u8A66\u8A08\u5283\u529F\u80FD\u7528\u4F8B\u7684\u6E2C\u8A66\u8A08\u5283ID\u9577\u5EA6\u904E\u9577
test_plan_function_case.test_plan_id.not_blank=\u6E2C\u8A66\u8A08\u5283\u529F\u80FD\u7528\u4F8B\u7684\u6E2C\u8A66\u8A08\u5283ID\u4E0D\u80FD\u70BA\u7A7A
test_plan_function_case.function_case_id.length_range=\u6E2C\u8A66\u8A08\u5283\u529F\u80FD\u7528\u4F8B\u7684\u529F\u80FD\u7528\u4F8BID\u9577\u5EA6\u904E\u9577
test_plan_function_case.function_case_id.not_blank=\u6E2C\u8A66\u8A08\u5283\u529F\u80FD\u7528\u4F8B\u7684\u529F\u80FD\u7528\u4F8BID\u4E0D\u80FD\u70BA\u7A7A
test_plan_function_case.create_user.length_range=\u6E2C\u8A66\u8A08\u5283\u529F\u80FD\u7528\u4F8B\u5275\u5EFA\u4EBA\u9577\u5EA6\u904E\u9577
test_plan_function_case.create_user.not_blank=\u6E2C\u8A66\u8A08\u5283\u529F\u80FD\u7528\u4F8B\u5275\u5EFA\u4EBA\u4E0D\u80FD\u70BA\u7A7A
test_plan_api_scenario.id.not_blank=\u6E2C\u8A66\u8A08\u5283API\u5834\u666FID\u4E0D\u80FD\u70BA\u7A7A
test_plan_api_scenario.test_plan_id.length_range=\u6E2C\u8A66\u8A08\u5283ID\u9577\u5EA6\u904E\u9577
test_plan_api_scenario.test_plan_id.not_blank=\u6E2C\u8A66\u8A08\u5283ID\u4E0D\u80FD\u70BA\u7A7A
test_plan_api_scenario.api_scenario_id.length_range=\u6E2C\u8A66\u8A08\u5283Api\u5834\u666F\u7684Api\u5834\u666FID\u9577\u5EA6\u904E\u9577
test_plan_api_scenario.api_scenario_id.not_blank=\u6E2C\u8A66\u8A08\u5283Api\u5834\u666F\u7684Api\u5834\u666FID\u4E0D\u80FD\u70BA\u7A7A
test_plan_api_scenario.create_user.length_range=\u6E2C\u8A66\u8A08\u5283API\u5834\u666F\u5275\u5EFA\u4EBA\u9577\u5EA6\u904E\u9577
test_plan_api_scenario.create_user.not_blank=\u6E2C\u8A66\u8A08\u5283API\u5834\u666F\u5275\u5EFA\u4EBA\u4E0D\u80FD\u70BA\u7A7A
test_plan_follow.test_plan_id.not_blan=\u6E2C\u8A66\u8A08\u5283ID\u4E0D\u80FD\u70BA\u7A7A
test_plan_follow.user_id.not_blank=\u7528\u6236ID\u4E0D\u80FD\u70BA\u7A7A
test_plan_api_case.id.not_blank=\u6E2C\u8A66\u8A08\u5283API\u7528\u4F8BID\u4E0D\u80FD\u70BA\u7A7A
test_plan_api_case.test_plan_id.length_range=\u6E2C\u8A66\u8A08\u5283API\u7528\u4F8B\u7684\u6E2C\u8A66\u8A08\u5283ID\u9577\u5EA6\u904E\u9577
test_plan_api_case.test_plan_id.not_blank=\u6E2C\u8A66\u8A08\u5283API\u7528\u4F8B\u7684\u6E2C\u8A66\u8A08\u5283ID\u4E0D\u80FD\u70BA\u7A7A
test_plan_api_case.api_case_id.length_range=\u6E2C\u8A66\u8A08\u5283API\u7528\u4F8B\u7684API\u7528\u4F8BID\u9577\u5EA6\u904E\u9577
test_plan_api_case.api_case_id.not_blank=\u6E2C\u8A66\u8A08\u5283API\u7528\u4F8B\u7684API\u7528\u4F8BID\u4E0D\u80FD\u70BA\u7A7A
test_plan_api_case.create_user.length_range=\u6E2C\u8A66\u8A08\u5283API\u7528\u4F8B\u5275\u5EFA\u4EBA\u9577\u5EA6\u904E\u9577
test_plan_api_case.create_user.not_blank=\u6E2C\u8A66\u8A08\u5283API\u7528\u4F8B\u5275\u5EFA\u4EBA\u4E0D\u80FD\u70BA\u7A7A
test_plan_config.test_plan_id.not_blank=\u6E2C\u8A66\u8A08\u5283ID\u4E0D\u80FD\u70BA\u7A7A
test_plan_config.automatic_status_update.length_range=\u81EA\u52D5\u72C0\u614B\u66F4\u65B0\u9577\u5EA6\u904E\u9577
test_plan_config.automatic_status_update.not_blank=\u81EA\u52D5\u72C0\u614B\u66F4\u65B0\u4E0D\u80FD\u70BA\u7A7A
test_plan_config.repeat_case.length_range=\u91CD\u8907\u7528\u4F8B\u9577\u5EA6\u904E\u9577
test_plan_config.repeat_case.not_blank=\u91CD\u8907\u7528\u4F8B\u4E0D\u80FD\u70BA\u7A7A
test_plan_config.pass_threshold.length_range=\u901A\u904E\u95BE\u503C\u9577\u5EA6\u904E\u9577
test_plan_config.pass_threshold.not_blank=\u901A\u904E\u95BE\u503C\u4E0D\u80FD\u70BA\u7A7A
test_plan_load_case.id.not_blank=\u6E2C\u8A66\u8A08\u5283\u6027\u80FD\u7528\u4F8BID\u4E0D\u80FD\u70BA\u7A7A
test_plan_load_case.test_plan_id.length_range=\u6E2C\u8A66\u8A08\u5283\u6027\u80FD\u7528\u4F8B\u7684\u6E2C\u8A66\u8A08\u5283ID\u9577\u5EA6\u904E\u9577
test_plan_load_case.test_plan_id.not_blank=\u6E2C\u8A66\u8A08\u5283\u6027\u80FD\u7528\u4F8B\u7684\u6E2C\u8A66\u8A08\u5283ID\u4E0D\u80FD\u70BA\u7A7A
test_plan_load_case.load_case_id.length_range=\u6E2C\u8A66\u8A08\u5283\u6027\u80FD\u7528\u4F8B\u7684\u6027\u80FD\u7528\u4F8BID\u9577\u5EA6\u904E\u9577
test_plan_load_case.load_case_id.not_blank=\u6E2C\u8A66\u8A08\u5283\u6027\u80FD\u7528\u4F8B\u7684\u6027\u80FD\u7528\u4F8BID\u4E0D\u80FD\u70BA\u7A7A
test_plan_load_case.create_user.length_range=\u6E2C\u8A66\u8A08\u5283\u6027\u80FD\u7528\u4F8B\u5275\u5EFA\u4EBA\u9577\u5EA6\u904E\u9577
test_plan_load_case.create_user.not_blank=\u6E2C\u8A66\u8A08\u5283\u6027\u80FD\u7528\u4F8B\u5275\u5EFA\u4EBA\u4E0D\u80FD\u70BA\u7A7A
test_plan_execute_record_blob.test_plan_execute_record.not_blank=\u6E2C\u8A66\u8A08\u5283\u57F7\u884C\u8A18\u9304\u4E0D\u80FD\u70BA\u7A7A
test_plan_execute_record.id.not_blank=\u6E2C\u8A66\u8A08\u5283\u57F7\u884C\u8A18\u9304ID\u4E0D\u80FD\u70BA\u7A7A
test_plan_execute_record.test_plan_id.length_range=\u6E2C\u8A66\u8A08\u5283ID\u9577\u5EA6\u904E\u9577
test_plan_execute_record.test_plan_id.not_blank=\u6E2C\u8A66\u8A08\u5283ID\u4E0D\u80FD\u70BA\u7A7A
test_plan_execute_record.name.length_range=\u6E2C\u8A66\u8A08\u5283\u57F7\u884C\u8A18\u9304\u540D\u7A31\u9577\u5EA6\u904E\u9577
test_plan_execute_record.name.not_blank=\u6E2C\u8A66\u8A08\u5283\u57F7\u884C\u8A18\u9304\u540D\u7A31\u4E0D\u80FD\u70BA\u7A7A
test_plan_execute_record.status.length_range=\u6E2C\u8A66\u8A08\u5283\u57F7\u884C\u8A18\u9304\u72C0\u614B\u9577\u5EA6\u904E\u9577
test_plan_execute_record.status.not_blank=\u6E2C\u8A66\u8A08\u5283\u57F7\u884C\u8A18\u9304\u72C0\u614B\u4E0D\u80FD\u70BA\u7A7A
test_plan_principal.test_plan_id.not_blank=\u6E2C\u8A66\u8A08\u5283ID\u4E0D\u80FD\u70BA\u7A7A
test_plan_principal.user_id.not_blank=\u7528\u6236ID\u4E0D\u80FD\u70BA\u7A7A
test_plan_report_content.id.not_blank=\u6E2C\u8A66\u8A08\u5283\u5831\u544A\u5167\u5BB9ID\u4E0D\u80FD\u70BA\u7A7A
test_plan_report_content.test_plan_report_id.length_range=\u6E2C\u8A66\u8A08\u5283\u5831\u544AID\u9577\u5EA6\u904E\u9577
test_plan_report_content.test_plan_report_id.not_blank=\u6E2C\u8A66\u8A08\u5283\u5831\u544AID\u4E0D\u80FD\u70BA\u7A7A
test_plan.id.not_blank=測試計劃id不能為空
test_plan.project_id.length_range=測試計劃所屬項目id長度過長
test_plan.project_id.not_blank=測試計劃所屬項目id不能為空
test_plan.module_id.not_blank=測試計劃模塊ID不能為空
test_plan.parent_id.length_range=測試計劃父id長度過長
test_plan.parent_id.not_blank=測試計劃父id不能為空
test_plan.name.length_range=測試計劃名稱長度過長
test_plan.name.not_blank=測試計劃名稱不能為空
test_plan.name.exist=測試計劃名稱已存在
test_plan.too_many=測試計劃數量不能超過{0}個
test_plan.status.length_range=測試計劃狀態長度過長
test_plan.status.not_blank=測試計劃狀態不能為空
test_plan.stage.length_range=測試計劃階段長度過長
test_plan.stage.not_blank=測試計劃階段不能為空
test_plan.create_user.length_range=測試計劃創建人長度過長
test_plan.create_user.not_blank=測試計劃創建人不能為空
test_plan_report.id.not_blank=測試計劃報告id不能為空
test_plan_report.test_plan_id.length_range=測試計劃id長度過長
test_plan_report.test_plan_id.not_blank=測試計劃id不能為空
test_plan_report.name.length_range=測試計劃報告名稱長度過長
test_plan_report.name.not_blank=測試計劃報告名稱不能為空
test_plan_report.create_user.length_range=測試計劃報告創建人長度過長
test_plan_report.create_user.not_blank=測試計劃報告創建人不能為空
test_plan_ui_scenario.id.not_blank=測試計劃ui用例id不能為空
test_plan_ui_scenario.test_plan_id.length_range=測試計劃ui用例的測試計劃id長度過長
test_plan_ui_scenario.test_plan_id.not_blank=測試計劃ui用例的測試計劃id不能為空
test_plan_ui_scenario.ui_scenario_id.length_range=測試計劃ui用例的ui用例id長度過長
test_plan_ui_scenario.ui_scenario_id.not_blank=測試計劃ui用例的ui用例id不能為空
test_plan_ui_scenario.create_user.length_range=測試計劃ui用例創建人長度過長
test_plan_ui_scenario.create_user.not_blank=測試計劃ui用例創建人不能為空
test_plan_function_case.id.not_blank=測試計劃功能用例id不能為空
test_plan_function_case.test_plan_id.length_range=測試計劃功能用例的測試計劃id長度過長
test_plan_function_case.test_plan_id.not_blank=測試計劃功能用例的測試計劃id不能為空
test_plan_function_case.function_case_id.length_range=測試計劃功能用例的功能用例id長度過長
test_plan_function_case.function_case_id.not_blank=測試計劃功能用例的功能用例id不能為空
test_plan_function_case.create_user.length_range=測試計劃功能用例創建人長度過長
test_plan_function_case.create_user.not_blank=測試計劃功能用例創建人不能為空
test_plan_api_scenario.id.not_blank=測試計劃api場景id不能為空
test_plan_api_scenario.test_plan_id.length_range=測試計劃id長度過長
test_plan_api_scenario.test_plan_id.not_blank=測試計劃id不能為空
test_plan_api_scenario.api_scenario_id.length_range=測試計劃api場景的api場景id長度過長
test_plan_api_scenario.api_scenario_id.not_blank=測試計劃api場景的api場景id不能為空
test_plan_api_scenario.create_user.length_range=測試計劃api場景創建人長度過長
test_plan_api_scenario.create_user.not_blank=測試計劃api場景創建人不能為空
test_plan_follow.test_plan_id.not_blan=測試計劃id不能為空
test_plan_follow.user_id.not_blank=用戶id不能為空
test_plan_api_case.id.not_blank=測試計劃api用例id不能為空
test_plan_api_case.test_plan_id.length_range=測試計劃api用例的測試計劃id長度過長
test_plan_api_case.test_plan_id.not_blank=測試計劃api用例的測試計劃id不能為空
test_plan_api_case.api_case_id.length_range=測試計劃api用例的api用例id長度過長
test_plan_api_case.api_case_id.not_blank=測試計劃api用例的api用例id不能為空
test_plan_api_case.create_user.length_range=測試計劃api用例創建人長度過長
test_plan_api_case.create_user.not_blank=測試計劃api用例創建人不能為空
test_plan_config.test_plan_id.not_blank=測試計劃id不能為空
test_plan_config.automatic_status_update.length_range=自動狀態更新長度過長
test_plan_config.automatic_status_update.not_blank=自動狀態更新不能為空
test_plan_config.repeat_case.length_range=重複用例長度過長
test_plan_config.repeat_case.not_blank=重複用例不能為空
test_plan_config.pass_threshold.length_range=通過閾值長度過長
test_plan_config.pass_threshold.not_blank=通過閾值不能為空
test_plan_load_case.id.not_blank=測試計劃性能用例id不能為空
test_plan_load_case.test_plan_id.length_range=測試計劃性能用例的測試計劃id長度過長
test_plan_load_case.test_plan_id.not_blank=測試計劃性能用例的測試計劃id不能為空
test_plan_load_case.load_case_id.length_range=測試計劃性能用例的性能用例id長度過長
test_plan_load_case.load_case_id.not_blank=測試計劃性能用例的性能用例id不能為空
test_plan_load_case.create_user.length_range=測試計劃性能用例創建人長度過長
test_plan_load_case.create_user.not_blank=測試計劃性能用例創建人不能為空
test_plan_execute_record_blob.test_plan_execute_record.not_blank=測試計劃執行記錄不能為空
test_plan_execute_record.id.not_blank=測試計劃執行記錄id不能為空
test_plan_execute_record.test_plan_id.length_range=測試計劃id長度過長
test_plan_execute_record.test_plan_id.not_blank=測試計劃id不能為空
test_plan_execute_record.name.length_range=測試計劃執行記錄名稱長度過長
test_plan_execute_record.name.not_blank=測試計劃執行記錄名稱不能為空
test_plan_execute_record.status.length_range=測試計劃執行記錄狀態長度過長
test_plan_execute_record.status.not_blank=測試計劃執行記錄狀態不能為空
test_plan_principal.test_plan_id.not_blank=測試計劃id不能為空
test_plan_principal.user_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.not_blank=測試計劃報告id不能為空
log.delete.test_plan=刪除測試計劃
log.delete.test_plan_group=刪除測試計劃組

View File

@ -444,9 +444,9 @@ latest.file.not.exist=最新文件不存在
file.not.jar=不是jar文件
change.jar.enable=修改了jar文件的启用状态
file.name.exist=文件名已存在
file.log.delete_module=模块下的所有数据全部被删除
log.delete_module=模块下的所有数据全部被删除
file.module.root=根目录
file.folder.error=文件夹不合法
folder.error=文件夹不合法
file.log.move_to=移动到
file.log.change_file_module=文件进行了移动
file.log.next=之后

View File

@ -480,9 +480,9 @@ latest.file.not.exist=New version file note exist
file.not.jar=Not jar file
change.jar.enable=Change jar file enable
file.name.exist=File name already exists
file.log.delete_module=has be deleted
log.delete_module=has be deleted
file.module.root=root module
file.folder.error=File folder error
folder.error=File folder error
file.log.move_to=move to
file.log.change_file_module=File has be moved
file.log.next=next

View File

@ -479,9 +479,9 @@ latest.file.not.exist=最新文件不存在
file.not.jar=不是jar文件
change.jar.enable=修改了jar文件的启用状态
file.name.exist=文件名已存在
file.log.delete_module=模块下的所有数据全部被删除
log.delete_module=模块下的所有数据全部被删除
file.module.root=根目录
file.folder.error=文件夹不合法
folder.error=文件夹不合法
file.log.move_to=移动到
file.log.change_file_module=文件进行了移动
file.log.next=之后

View File

@ -480,9 +480,9 @@ latest.file.not.exist=最新文件不存在
file.not.jar=不是jar文件
change.jar.enable=修改了jar文件的啟用狀態
file.name.exist=文件名已存在
file.log.delete_module=模塊下的所有數據全部被刪除
log.delete_module=模塊下的所有數據全部被刪除
file.module.root=根目錄
file.folder.error=文件夾不合法
folder.error=文件夾不合法
file.log.move_to=移動到
file.log.change_file_module=文件進行了移動
file.log.next=之後

View File

@ -85,7 +85,7 @@ public class ApiDebugModuleLogService {
.method(HttpMethodConstants.GET.name())
.path(DELETE + "/%s")
.sourceId(item.getId())
.content(item.getName() + " " + Translator.get("file.log.delete_module"))
.content(item.getName() + " " + Translator.get("log.delete_module"))
.createUser(operator)
.build().getLogDTO();
dtos.add(dto);

View File

@ -86,7 +86,7 @@ public class ApiDefinitionModuleLogService {
.method(HttpMethodConstants.GET.name())
.path(DELETE + "/%s")
.sourceId(item.getId())
.content(item.getName() + " " + Translator.get("file.log.delete_module"))
.content(item.getName() + " " + Translator.get("log.delete_module"))
.createUser(operator)
.build().getLogDTO();
dtoList.add(dto);

View File

@ -85,7 +85,7 @@ public class ApiScenarioModuleLogService {
.method(HttpMethodConstants.GET.name())
.path(DELETE + "/%s")
.sourceId(item.getId())
.content(item.getName() + " " + Translator.get("file.log.delete_module"))
.content(item.getName() + " " + Translator.get("log.delete_module"))
.createUser(operator)
.build().getLogDTO();
dtoList.add(dto);

View File

@ -8,5 +8,7 @@ VALUES ('wx_test_id_1', 'wx_1', 'bug_id_1', 'FUNCTIONAL', null, null, 'admin', U
('wx_test_id_2', 'wx_2', 'bug_id_1', 'FUNCTIONAL', 'test-plan-id', 'bug_relate_case', 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000),
('wx_test_id_3', 'wx_3', 'bug_id_2', 'FUNCTIONAL', null, null, 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000);
INSERT INTO `test_plan` (`id`,`project_id`,`parent_id`,`name`,`status`,`stage`,`create_time`,`create_user`)
VALUES('test-plan-id','wx_test','3','cececec','3','4',UNIX_TIMESTAMP() * 1000,'admin');
INSERT INTO `test_plan` (`id`, `project_id`, `group_id`, `module_id`, `type`, `name`, `status`, `create_time`,
`create_user`)
VALUES ('test-plan-id', 'wx_test', 'none', 'root', 'TEST_PLAN', 'cececec', 'PREPARED', UNIX_TIMESTAMP() * 1000,
'admin');

View File

@ -280,8 +280,6 @@ public class FileMetadataService {
}
}
private static final String FILE_MODULE_COUNT_ALL = "all";
private String uploadFile(FileMetadata fileMetadata, MultipartFile file) throws Exception {
FileRequest uploadFileRequest = new FileRequest();
uploadFileRequest.setFileName(fileMetadata.getId());
@ -414,8 +412,6 @@ public class FileMetadataService {
}
}
private static final String FILE_MODULE_COUNT_MY = "my";
/**
* 重新上传
*/
@ -466,8 +462,8 @@ public class FileMetadataService {
long allCount = extFileMetadataMapper.fileCount(myFileCountDTO);
myFileCountDTO.setOperator(operator);
long myFileCount = extFileMetadataMapper.fileCount(myFileCountDTO);
moduleCountMap.put(FILE_MODULE_COUNT_MY, myFileCount);
moduleCountMap.put(FILE_MODULE_COUNT_ALL, allCount);
moduleCountMap.put(ModuleConstants.MODULE_COUNT_MY, myFileCount);
moduleCountMap.put(ModuleConstants.MODULE_COUNT_ALL, allCount);
return moduleCountMap;
}

View File

@ -105,9 +105,9 @@ public class FileModuleLogService {
.type(OperationLogType.DELETE.name())
.module(OperationLogModule.PROJECT_FILE_MANAGEMENT)
.method(HttpMethodConstants.GET.name())
.path("/project/file-module/delete/%s")
.path("/project/file-module/delete")
.sourceId(deleteModule.getId())
.content(deleteModule.getName() + " " + Translator.get("file.log.delete_module"))
.content(deleteModule.getName() + " " + Translator.get("log.delete_module"))
.originalValue(JSON.toJSONBytes(deleteModule))
.createUser(operator)
.build().getLogDTO();

View File

@ -31,10 +31,9 @@ import io.metersphere.system.log.constants.OperationLogModule;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.service.CommonProjectService;
import io.metersphere.system.uid.IDGenerator;
import io.metersphere.system.utils.CheckLogModel;
import io.metersphere.system.utils.Pager;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.junit.jupiter.api.*;
@ -2479,11 +2478,3 @@ public class FileManagementControllerTests extends BaseTest {
}
}
}
@Data
@AllArgsConstructor
class CheckLogModel {
private String resourceId;
private OperationLogType operationType;
private String url;
}

View File

@ -22,10 +22,9 @@ import io.metersphere.system.log.constants.OperationLogModule;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.service.CommonProjectService;
import io.metersphere.system.uid.IDGenerator;
import io.metersphere.system.utils.CheckLogModel;
import io.metersphere.system.utils.Pager;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.apache.commons.collections4.CollectionUtils;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
@ -68,7 +67,7 @@ public class FileRepositoryControllerTest extends BaseTest {
@Resource
private CommonProjectService commonProjectService;
private static List<RepositoryCheckLogModel> LOG_CHECK_LIST = new ArrayList<>();
private static List<CheckLogModel> LOG_CHECK_LIST = new ArrayList<>();
@BeforeEach
public void initTestData() {
@ -167,7 +166,7 @@ public class FileRepositoryControllerTest extends BaseTest {
repositoryId = rh.getData().toString();
this.checkFileRepository(repositoryId, createRequest.getProjectId(), createRequest.getName(), createRequest.getPlatform(), createRequest.getUrl(), createRequest.getToken(), createRequest.getUserName());
LOG_CHECK_LIST.add(
new RepositoryCheckLogModel(repositoryId, OperationLogType.ADD, FileManagementRequestUtils.URL_FILE_REPOSITORY_CREATE)
new CheckLogModel(repositoryId, OperationLogType.ADD, FileManagementRequestUtils.URL_FILE_REPOSITORY_CREATE)
);
//测试获取详情
@ -213,7 +212,7 @@ public class FileRepositoryControllerTest extends BaseTest {
rh = JSON.parseObject(returnStr, ResultHolder.class);
this.checkFileRepository(rh.getData().toString(), createRequest.getProjectId(), createRequest.getName(), createRequest.getPlatform(), createRequest.getUrl(), createRequest.getToken(), createRequest.getUserName());
LOG_CHECK_LIST.add(
new RepositoryCheckLogModel(rh.getData().toString(), OperationLogType.ADD, FileManagementRequestUtils.URL_FILE_REPOSITORY_CREATE)
new CheckLogModel(rh.getData().toString(), OperationLogType.ADD, FileManagementRequestUtils.URL_FILE_REPOSITORY_CREATE)
);
//参数测试 没有url
@ -288,7 +287,7 @@ public class FileRepositoryControllerTest extends BaseTest {
this.requestPostWithOkAndReturn(FileManagementRequestUtils.URL_FILE_REPOSITORY_UPDATE, createRequest);
this.checkFileRepository(repositoryId, project.getId(), "GITEA存储库改个名字", ModuleConstants.NODE_TYPE_GITEA, GITEA_URL, GITEA_TOKEN, null);
LOG_CHECK_LIST.add(
new RepositoryCheckLogModel(repositoryId, OperationLogType.UPDATE, FileManagementRequestUtils.URL_FILE_REPOSITORY_UPDATE)
new CheckLogModel(repositoryId, OperationLogType.UPDATE, FileManagementRequestUtils.URL_FILE_REPOSITORY_UPDATE)
);
//修改用户名
FileModuleRepository updateModel = new FileModuleRepository();
@ -344,7 +343,7 @@ public class FileRepositoryControllerTest extends BaseTest {
this.requestGetWithOk(String.format(FileManagementRequestUtils.URL_MODULE_DELETE, repositoryId));
this.checkRepositoryDeleted(repositoryId);
LOG_CHECK_LIST.add(
new RepositoryCheckLogModel(repositoryId, OperationLogType.DELETE, FileManagementRequestUtils.URL_MODULE_DELETE)
new CheckLogModel(repositoryId, OperationLogType.DELETE, FileManagementRequestUtils.URL_MODULE_DELETE)
);
//重新添加
@ -360,7 +359,7 @@ public class FileRepositoryControllerTest extends BaseTest {
repositoryId = rh.getData().toString();
this.checkFileRepository(repositoryId, createRequest.getProjectId(), createRequest.getName(), createRequest.getPlatform(), createRequest.getUrl(), createRequest.getToken(), createRequest.getUserName());
LOG_CHECK_LIST.add(
new RepositoryCheckLogModel(repositoryId, OperationLogType.ADD, FileManagementRequestUtils.URL_FILE_REPOSITORY_CREATE)
new CheckLogModel(repositoryId, OperationLogType.ADD, FileManagementRequestUtils.URL_FILE_REPOSITORY_CREATE)
);
}
@ -410,7 +409,7 @@ public class FileRepositoryControllerTest extends BaseTest {
String fileId = JSON.parseObject(result.getResponse().getContentAsString(), ResultHolder.class).getData().toString();
this.checkRepositoryFile(fileId, request);
LOG_CHECK_LIST.add(
new RepositoryCheckLogModel(fileId, OperationLogType.ADD, FileManagementRequestUtils.URL_FILE_REPOSITORY_FILE_ADD)
new CheckLogModel(fileId, OperationLogType.ADD, FileManagementRequestUtils.URL_FILE_REPOSITORY_FILE_ADD)
);
getFileMessage(fileId);
fileList.add(fileId);
@ -661,7 +660,7 @@ public class FileRepositoryControllerTest extends BaseTest {
this.requestPostWithOk(FileManagementRequestUtils.URL_FILE_DELETE, fileBatchProcessRequest);
for (String fileId : fileList) {
LOG_CHECK_LIST.add(
new RepositoryCheckLogModel(fileId, OperationLogType.DELETE, FileManagementRequestUtils.URL_FILE_DELETE)
new CheckLogModel(fileId, OperationLogType.DELETE, FileManagementRequestUtils.URL_FILE_DELETE)
);
this.checkRepositoryFileDeleted(fileId);
}
@ -671,7 +670,7 @@ public class FileRepositoryControllerTest extends BaseTest {
@Order(100)
public void testLog() throws Exception {
Thread.sleep(5000);
for (RepositoryCheckLogModel checkLogModel : LOG_CHECK_LIST) {
for (CheckLogModel checkLogModel : LOG_CHECK_LIST) {
if (org.apache.commons.lang3.StringUtils.isEmpty(checkLogModel.getUrl())) {
this.checkLog(checkLogModel.getResourceId(), checkLogModel.getOperationType());
} else {
@ -717,12 +716,4 @@ public class FileRepositoryControllerTest extends BaseTest {
ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class);
return JSON.parseArray(JSON.toJSONString(resultHolder.getData()), String.class);
}
}
@Data
@AllArgsConstructor
class RepositoryCheckLogModel {
private String resourceId;
private OperationLogType operationType;
private String url;
}

View File

@ -8,6 +8,7 @@ import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
@ -20,7 +21,7 @@ public class TableBatchProcessDTO {
private List<
@NotBlank(message = "{id must not be blank}", groups = {Created.class, Updated.class})
String
> selectIds;
> selectIds = new ArrayList<>();
@Schema(description = "是否选择所有数据")
private boolean selectAll;

View File

@ -0,0 +1,27 @@
package io.metersphere.system.utils;
import io.metersphere.system.log.constants.OperationLogType;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
@Data
public class CheckLogModel {
private String resourceId;
private OperationLogType operationType;
private String url;
public CheckLogModel(String resourceId, OperationLogType operationType, String url) {
this.resourceId = resourceId;
this.operationType = operationType;
this.url = formatLogUrl(url);
}
private String formatLogUrl(String url) {
if (StringUtils.endsWith(url, "/%s")) {
return StringUtils.substring(url, 0, url.length() - 3);
} else {
return url;
}
}
}

View File

@ -40,8 +40,12 @@ VALUES ('aspect_gyq_api_one', 'api_test','HTTP', 'POST','api/test','test-api-sta
INSERT INTO api_scenario(id, name, priority, status, last_report_status, last_report_id, num, pos, version_id, ref_id, project_id, module_id, description, tags, create_user, create_time, delete_time, delete_user, update_user, update_time)
VALUES ('aspect_gyq_api_scenario_one', 'api_scenario', 'p1', 'test-api-status', null, null,1000001, 1,'v1.10', 'aspect_gyq_api_scenario_one','100001100001', 'test_module', null,null,'admin', UNIX_TIMESTAMP() * 1000,null,null,'admin', UNIX_TIMESTAMP() * 1000);
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 test_plan(id, 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,
actual_end_time, description)
VALUES ('aspect_gyq_test_plan_one', '100001100001', 'none', 'root', 'test_plan', 'PREPARED', 'TEST_PLAN', 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, 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');

View File

@ -1,41 +1,116 @@
package io.metersphere.plan.controller;
import io.metersphere.plan.dto.TestPlanDTO;
import io.metersphere.plan.dto.request.TestPlanBatchProcessRequest;
import io.metersphere.plan.dto.request.TestPlanCreateRequest;
import io.metersphere.plan.dto.request.TestPlanTableRequest;
import io.metersphere.plan.dto.response.TestPlanResponse;
import io.metersphere.plan.service.TestPlanManagementService;
import io.metersphere.plan.service.TestPlanService;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.constants.HttpMethodConstants;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.system.security.CheckOwner;
import io.metersphere.system.utils.Pager;
import io.metersphere.system.utils.SessionUtils;
import io.metersphere.validation.groups.Created;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotBlank;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/test-plan")
@Tag(name = "测试计划")
public class TestPlanController {
@Resource
private TestPlanService testPlanService;
@Resource
private TestPlanManagementService testPlanManagementService;
@PostMapping("/page")
@Operation(summary = "测试计划-表格分页查询")
@RequiresPermissions(PermissionConstants.TEST_PLAN_READ)
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
public Pager<List<TestPlanResponse>> page(@Validated @RequestBody TestPlanTableRequest request) {
return testPlanManagementService.page(request);
}
@GetMapping("/getCount/{id}")
@Operation(summary = "测试计划-获取统计数据")
@RequiresPermissions(PermissionConstants.TEST_PLAN_READ)
@CheckOwner(resourceId = "#id", resourceType = "test_plan")
public TestPlanResponse getCount(@PathVariable String id) {
return testPlanService.getCount(id);
}
@PostMapping("/module/count")
@Operation(summary = "测试计划-模块统计")
@RequiresPermissions(PermissionConstants.TEST_PLAN_READ)
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
public Map<String, Long> moduleCount(@Validated @RequestBody TestPlanTableRequest request) {
return testPlanManagementService.moduleCount(request);
}
@PostMapping("/add")
public TestPlanDTO addUser(@Validated({Created.class}) @RequestBody TestPlanDTO testPlan) {
testPlan.setCreateUser(SessionUtils.getUserId());
testPlan.setUpdateUser(SessionUtils.getUserId());
return testPlanService.add(testPlan);
@Operation(summary = "测试计划-创建测试计划")
@RequiresPermissions(PermissionConstants.TEST_PLAN_READ_ADD)
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
public String add(@Validated @RequestBody TestPlanCreateRequest testPlan) {
return testPlanService.add(testPlan, SessionUtils.getUserId(), "/test-plan/add", HttpMethodConstants.POST.name());
}
@PostMapping("/delete/batch")
public void deleteBatch(@RequestBody List<String> idList) {
if (CollectionUtils.isEmpty(idList)) {
throw new MSException("The ids cannot be empty!");
}
testPlanService.batchDelete(idList);
}
@GetMapping("/delete/{id}")
@Operation(summary = "测试计划-删除测试计划")
@RequiresPermissions(PermissionConstants.TEST_PLAN_READ_DELETE)
@CheckOwner(resourceId = "#id", resourceType = "test_plan")
public void delete(@NotBlank @PathVariable String id) {
testPlanService.delete(id);
testPlanService.delete(id, SessionUtils.getUserId(), "/test-plan/delete", HttpMethodConstants.GET.name());
}
@PostMapping(value = "/batch-delete")
@Operation(summary = "测试计划-批量删除")
@RequiresPermissions(PermissionConstants.PROJECT_FILE_MANAGEMENT_READ_DELETE)
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
public void delete(@Validated @RequestBody TestPlanBatchProcessRequest request) throws Exception {
testPlanService.delete(request, SessionUtils.getUserId(), "/test-plan/batch-delete", HttpMethodConstants.POST.name());
}
/*
todo 更新接口具体字段未确定
@PostMapping(value = "/update")
@Operation(summary = "项目管理-文件管理-修改文件")
@RequiresPermissions(PermissionConstants.PROJECT_FILE_MANAGEMENT_READ_UPDATE)
@CheckOwner(resourceId = "#request.getId()", resourceType = "file_metadata")
public void update(@Validated @RequestBody FileUpdateRequest request) throws Exception {
}
*/
//todo 关注测试计划接口
//todo 取消关注测试计划接口
/*
todo 归档测试计划
·归档时要确定测试计划是完成状态
·归档时所有数据要备份一套新的包括各种用例的基本信息
·关于环境但是在查看归档内容的时候所属环境展示什么只展示名字吗
·关于用例那么是要在测试计划里能查看到用例的具体信息吗 不归档的测试计划能查看吗
·功能用例里涉及到评审相关的也要备份吗
·功能用例里关联的其他自动化用例信息也要备份吗
·缺陷的整个流转过程也是要备份吗
·关于报告
·备份到什么程度还需要在报告列表中展示这些报告吗
·每个用例调试出来的报告要备份吗全部都备份
·执行记录呢也要完全备份吗
·归档的测试计划从哪里看在测试计划列表中混合着展示吗还是提供一个单独的按钮/页面/模块单独展示这些归档了的东西
*/
}

View File

@ -1,27 +0,0 @@
package io.metersphere.plan.dto;
import io.metersphere.plan.domain.TestPlan;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
@EqualsAndHashCode(callSuper = true)
@Data
public class TestPlanDTO extends TestPlan {
@Schema(description = "测试计划责任人", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
private List<String> principals;
@Schema(description = "测试计划关注人")
private List<String> followers;
@Schema(description = "是否自定更新功能用例状态", requiredMode = Schema.RequiredMode.REQUIRED)
private boolean automaticStatusUpdate;
@Schema(description = "是否允许重复添加用例", requiredMode = Schema.RequiredMode.REQUIRED)
private boolean repeatCase;
@Schema(description = "测试计划通过阈值;0-100", requiredMode = Schema.RequiredMode.REQUIRED)
private int passThreshold = 100;
}

View File

@ -0,0 +1,37 @@
package io.metersphere.plan.dto;
import io.metersphere.sdk.constants.TestPlanConstants;
import io.metersphere.system.dto.sdk.BaseCondition;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
/**
* 测试计划条件查询
*/
@Data
@NoArgsConstructor
public class TestPlanQueryConditions {
//模块ID
private List<String> moduleIds;
//项目ID
private String projectId;
//测试计划所属GroupId
private String groupId = TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID;
//查询条件
private BaseCondition condition = new BaseCondition();
//隐藏的测试计划ID
public List<String> hiddenIds = new ArrayList<>();
public TestPlanQueryConditions(List<String > moduleIds,String projectId,BaseCondition condition){
this.moduleIds = moduleIds;
this.projectId = projectId;
this.condition = condition;
}
}

View File

@ -0,0 +1,22 @@
package io.metersphere.plan.dto.request;
import io.metersphere.system.dto.table.TableBatchProcessDTO;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
@Data
@EqualsAndHashCode(callSuper = false)
public class TestPlanBatchProcessRequest extends TableBatchProcessDTO {
@Schema(description = "项目ID")
@NotBlank(message = "{id must not be blank}")
private String projectId;
@Schema(description = "模块ID")
private List<String> moduleIds;
}

View File

@ -0,0 +1,65 @@
package io.metersphere.plan.dto.request;
import io.metersphere.sdk.constants.ModuleConstants;
import io.metersphere.sdk.constants.TestPlanConstants;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.Data;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
@Data
public class TestPlanCreateRequest {
@Schema(description = "测试计划所属项目", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan.project_id.not_blank}")
@Size(min = 1, max = 50, message = "{test_plan.project_id.length_range}")
private String projectId;
@Schema(description = "测试计划组ID;测试计划要改为树结构。最上层的为root其余则是父节点ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan.parent_id.not_blank}")
@Size(min = 1, max = 50, message = "{test_plan.parent_id.length_range}")
private String groupId = TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID;
@Schema(description = "测试计划名称", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan.name.not_blank}")
@Size(min = 1, max = 255, message = "{test_plan.name.length_range}")
private String name;
@Schema(description = "测试计划模块ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan.module_id.not_blank}")
@Size(min = 1, max = 50, message = "{test_plan.parent_id.length_range}")
private String moduleId = ModuleConstants.DEFAULT_NODE_ID;
@Schema(description = "计划开始时间")
private Long plannedStartTime;
@Schema(description = "计划结束时间")
private Long plannedEndTime;
@Schema(description = "标签")
private LinkedHashSet<
@NotBlank
String> tags;
@Schema(description = "描述")
private String description;
@Schema(description = "是否自定更新功能用例状态", requiredMode = Schema.RequiredMode.REQUIRED)
private boolean automaticStatusUpdate;
@Schema(description = "是否允许重复添加用例", requiredMode = Schema.RequiredMode.REQUIRED)
private boolean repeatCase;
@Schema(description = "测试计划通过阈值;0-100", requiredMode = Schema.RequiredMode.REQUIRED)
@Max(value = 100, message = "{test_plan.pass_threshold.max}")
private double passThreshold = 100;
public List<String> getTags() {
return tags == null ? null : new ArrayList<>(tags);
}
}

View File

@ -0,0 +1,25 @@
package io.metersphere.plan.dto.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 lombok.EqualsAndHashCode;
import java.util.List;
@Data
@EqualsAndHashCode(callSuper = false)
public class TestPlanTableRequest extends BasePageRequest {
@Schema(description = "模块ID(根据模块树查询时要把当前节点以及子节点都放在这里。)")
private List<String> moduleIds;
@Schema(description = "项目ID")
@NotBlank(message = "{id must not be blank}")
private String projectId;
public TestPlanTableRequest() {
this.setCurrent(1);
this.setPageSize(5);
}
}

View File

@ -0,0 +1,41 @@
package io.metersphere.plan.dto.response;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
public class TestPlanResponse {
//ID计划名称计划状态测试进度通过率用例数定时任务bug数创建人创建时间模块
@Schema(description = "测试计划ID")
private String id;
@Schema(description = "测试计划编号")
private long num;
@Schema(description = "名称")
private String name;
@Schema(description = "状态")
private String status;
@Schema(description = "测试进度")
private String testProgress;
@Schema(description = "通过率")
private String passRate;
@Schema(description = "功能用例数")
private long functionalCaseCount = -1;
@Schema(description = "接口用例数")
private long apiCaseCount = -1;
@Schema(description = "接口场景数")
private long apiScenarioCount = -1;
@Schema(description = "Bug数量")
private long bugCount = -1;
@Schema(description = "定时任务")
private String schedule;
@Schema(description = "创建人")
private String createUser;
@Schema(description = "创建时间")
private String createTime;
@Schema(description = "模块")
private String moduleName;
@Schema(description = "模块Id")
private String moduleId;
@Schema(description = "类型(测试计划组/测试计划)")
private String type;
}

View File

@ -1,11 +1,21 @@
package io.metersphere.plan.mapper;
import io.metersphere.plan.dto.TestPlanQueryConditions;
import io.metersphere.plan.dto.response.TestPlanResponse;
import io.metersphere.project.dto.ModuleCountDTO;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface ExtTestPlanMapper {
List<String> selectByParentId(String parentId);
List<String> selectByGroupId(String parentId);
List<String> selectByGroupIdList(@Param("list") List<String> parentTestPlanId);
List<TestPlanResponse> selectByConditions(TestPlanQueryConditions testPlanQueryConditions);
List<String> selectIdByConditions(TestPlanQueryConditions testPlanQueryConditions);
List<ModuleCountDTO> countModuleIdByKeywordAndFileType(TestPlanQueryConditions testPlanQueryConditions);
List<String> selectByParentIdList(@Param("list") List<String> parentTestPlanId);
}

View File

@ -2,13 +2,70 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="io.metersphere.plan.mapper.ExtTestPlanMapper">
<select id="selectByParentId" resultType="java.lang.String">
SELECT id FROM test_plan WHERE parent_id = #{parentId}
<select id="selectByGroupId" resultType="java.lang.String">
SELECT id FROM test_plan WHERE group_id = #{parentId}
</select>
<select id="selectByParentIdList" resultType="java.lang.String">
SELECT id FROM test_plan WHERE parent_id IN
<select id="selectByGroupIdList" resultType="java.lang.String">
SELECT id FROM test_plan WHERE group_id IN
<foreach collection="list" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>
<select id="selectByConditions"
parameterType="io.metersphere.plan.dto.TestPlanQueryConditions"
resultType="io.metersphere.plan.dto.response.TestPlanResponse">
SELECT
t.id,t.num,t.name,t.status,
createUser.name AS createUser,
t.create_time,
t.module_id,
t.type,
t.tags
FROM test_plan t
INNER JOIN user createUser ON t.create_user = createUser.id
<include refid="test_plan_page_request"/>
</select>
<select id="countModuleIdByKeywordAndFileType"
parameterType="io.metersphere.plan.dto.TestPlanQueryConditions"
resultType="io.metersphere.project.dto.ModuleCountDTO">
SELECT t.module_id AS moduleId, count(t.id) AS dataCount
FROM test_plan t
INNER JOIN user createUser ON t.create_user = createUser.id
<include refid="test_plan_page_request"/>
GROUP BY t.module_id
</select>
<select id="selectIdByConditions"
parameterType="io.metersphere.plan.dto.TestPlanQueryConditions"
resultType="java.lang.String">
SELECT
t.id
FROM test_plan t
INNER JOIN user createUser ON t.create_user = createUser.id
<include refid="test_plan_page_request"/>
</select>
<sql id="test_plan_page_request">
<where>
t.group_id = #{groupId}
<if test="projectId != null and projectId != ''">
AND t.project_id = #{projectId}
</if>
<if test="condition.keyword != null and condition.keyword != ''">
AND t.name like concat('%', #{condition.keyword}, '%')
</if>
<if test="moduleIds != null and moduleIds.size() != 0">
AND t.module_id IN
<foreach collection="moduleIds" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</if>
<if test="hiddenIds != null and hiddenIds.size()>0">
AND t.id NOT IN
<foreach collection="hiddenIds" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</if>
</where>
</sql>
</mapper>

View File

@ -25,4 +25,6 @@ public interface ExtTestPlanModuleMapper {
List<String> selectIdsByProjectId(String projectId);
List<String> selectChildrenIdsSortByPos(String parentId);
String selectNameById(String id);
}

View File

@ -63,4 +63,9 @@
WHERE parent_id = #{0}
ORDER BY pos ASC
</select>
<select id="selectNameById" resultType="java.lang.String">
SELECT name
FROM test_plan_module
WHERE id = #{0}
</select>
</mapper>

View File

@ -0,0 +1,98 @@
package io.metersphere.plan.service;
import io.metersphere.plan.domain.TestPlan;
import io.metersphere.project.domain.Project;
import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.sdk.constants.TestPlanConstants;
import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.dto.builder.LogDTOBuilder;
import io.metersphere.system.log.constants.OperationLogModule;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.log.dto.LogDTO;
import io.metersphere.system.log.service.OperationLogService;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Transactional(rollbackFor = Exception.class)
public class TestPlanLogService {
private String logModule = OperationLogModule.TEST_PLAN;
@Resource
private ProjectMapper projectMapper;
@Resource
private OperationLogService operationLogService;
public void saveAddLog(TestPlan module, String operator, String requestUrl, String requestMethod) {
Project project = projectMapper.selectByPrimaryKey(module.getProjectId());
LogDTO dto = LogDTOBuilder.builder()
.projectId(module.getProjectId())
.organizationId(project.getOrganizationId())
.type(OperationLogType.ADD.name())
.module(logModule)
.method(requestMethod)
.path(requestUrl)
.sourceId(module.getId())
.content(module.getName())
.originalValue(JSON.toJSONBytes(module))
.createUser(operator)
.build().getLogDTO();
operationLogService.add(dto);
}
public void saveUpdateLog(TestPlan oldTestPlan, TestPlan newTestPlan, String projectId, String operator, String requestUrl, String requestMethod) {
Project project = projectMapper.selectByPrimaryKey(projectId);
LogDTO dto = LogDTOBuilder.builder()
.projectId(projectId)
.organizationId(project.getOrganizationId())
.type(OperationLogType.UPDATE.name())
.module(logModule)
.method(requestMethod)
.path(requestUrl)
.sourceId(newTestPlan.getId())
.content(newTestPlan.getName())
.originalValue(JSON.toJSONBytes(oldTestPlan))
.modifiedValue(JSON.toJSONBytes(newTestPlan))
.createUser(operator)
.build().getLogDTO();
operationLogService.add(dto);
}
public void saveDeleteLog(TestPlan deleteTestPlan, List<TestPlan> testPlanItemList, String operator, String requestUrl, String requestMethod) {
Project project = projectMapper.selectByPrimaryKey(deleteTestPlan.getProjectId());
LogDTO dto = LogDTOBuilder.builder()
.projectId(deleteTestPlan.getProjectId())
.organizationId(project.getOrganizationId())
.type(OperationLogType.DELETE.name())
.module(logModule)
.method(requestMethod)
.path(requestUrl)
.sourceId(deleteTestPlan.getId())
.content(this.generateTestPlanDeleteContent(deleteTestPlan, testPlanItemList))
.originalValue(JSON.toJSONBytes(deleteTestPlan))
.createUser(operator)
.build().getLogDTO();
operationLogService.add(dto);
}
private String generateTestPlanDeleteContent(TestPlan deleteTestPlan, List<TestPlan> testPlanItemList) {
StringBuilder content = new StringBuilder();
if(StringUtils.equals(deleteTestPlan.getType(), TestPlanConstants.TEST_PLAN_TYPE_GROUP)){
content.append(Translator.get("log.delete.test_plan_group")).append(":").append(deleteTestPlan.getName()).append(StringUtils.SPACE);
}
if(CollectionUtils.isNotEmpty(testPlanItemList)){
List<String> testPlanNameList = testPlanItemList.stream().map(TestPlan::getName).toList();
String testPlanNamesString = StringUtils.join(testPlanNameList,",");
content.append(Translator.get("log.delete.test_plan")).append(":").append(testPlanNamesString).append(StringUtils.SPACE);
}
return content.toString();
}
}

View File

@ -0,0 +1,51 @@
package io.metersphere.plan.service;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.plan.dto.TestPlanQueryConditions;
import io.metersphere.plan.dto.request.TestPlanTableRequest;
import io.metersphere.plan.dto.response.TestPlanResponse;
import io.metersphere.plan.mapper.ExtTestPlanMapper;
import io.metersphere.project.dto.ModuleCountDTO;
import io.metersphere.system.utils.PageUtils;
import io.metersphere.system.utils.Pager;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Map;
@Service
@Transactional(rollbackFor = Exception.class)
public class TestPlanManagementService {
@Resource
private ExtTestPlanMapper extTestPlanMapper;
@Resource
private TestPlanModuleService testPlanModuleService;
public Map<String, Long> moduleCount(TestPlanTableRequest request) {
//查出每个模块节点下的资源数量 不需要按照模块进行筛选
TestPlanQueryConditions testPlanQueryConditions = new TestPlanQueryConditions(null, request.getProjectId(), request);
List<ModuleCountDTO> moduleCountDTOList = extTestPlanMapper.countModuleIdByKeywordAndFileType(testPlanQueryConditions);
Map<String, Long> moduleCountMap = testPlanModuleService.getModuleCountMap(request.getProjectId(), moduleCountDTOList);
return moduleCountMap;
}
public Pager<List<TestPlanResponse>> page(TestPlanTableRequest request) {
Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize(),
StringUtils.isNotBlank(request.getSortString()) ? request.getSortString() : "t.update_time desc");
return PageUtils.setPageInfo(page, this.getTableList(request));
}
private List<TestPlanResponse> getTableList(TestPlanTableRequest request) {
List<TestPlanResponse> testPlanResponses = extTestPlanMapper.selectByConditions(new TestPlanQueryConditions(request.getModuleIds(), request.getProjectId(), request));
testPlanResponses.forEach(item -> {
item.setModuleName(testPlanModuleService.getNameById(item.getModuleId()));
//todo 定时任务相关信息处理
});
return testPlanResponses;
}
}

View File

@ -73,7 +73,7 @@ public class TestPlanModuleLogService {
.method(requestMethod)
.path(requestUrl)
.sourceId(deleteModule.getId())
.content(deleteModule.getName() + " " + Translator.get("file.log.delete_module"))
.content(deleteModule.getName() + " " + Translator.get("log.delete_module"))
.originalValue(JSON.toJSONBytes(deleteModule))
.createUser(operator)
.build().getLogDTO();

View File

@ -1,5 +1,6 @@
package io.metersphere.plan.service;
import io.metersphere.plan.dto.request.TestPlanBatchProcessRequest;
import io.metersphere.plan.dto.request.TestPlanModuleCreateRequest;
import io.metersphere.plan.dto.request.TestPlanModuleUpdateRequest;
import io.metersphere.plan.mapper.ExtTestPlanModuleMapper;
@ -43,6 +44,8 @@ public class TestPlanModuleService extends ModuleTreeService implements CleanupP
protected SqlSessionFactory sqlSessionFactory;
@Resource
private TestPlanModuleLogService testPlanModuleLogService;
@Resource
private TestPlanService testPlanService;
public List<BaseTreeNode> getTree(String projectId) {
List<BaseTreeNode> fileModuleList = extTestPlanModuleMapper.selectBaseByProjectId(projectId);
@ -128,7 +131,7 @@ public class TestPlanModuleService extends ModuleTreeService implements CleanupP
public void update(TestPlanModuleUpdateRequest request, String userId,String requestUrl,String requestMethod) {
TestPlanModule module = testPlanModuleMapper.selectByPrimaryKey(request.getId());
if (module == null) {
throw new MSException("file_module.not.exist");
throw new MSException("module.not.exist");
}
TestPlanModule updateModule = new TestPlanModule();
updateModule.setId(request.getId());
@ -144,25 +147,29 @@ public class TestPlanModuleService extends ModuleTreeService implements CleanupP
}
public void deleteModule(String deleteId, String currentUser,String requestUrl,String requestMethod) {
public void deleteModule(String deleteId, String operator, String requestUrl, String requestMethod) {
TestPlanModule deleteModule = testPlanModuleMapper.selectByPrimaryKey(deleteId);
if (deleteModule != null) {
this.deleteModule(Collections.singletonList(deleteId));
this.deleteModule(Collections.singletonList(deleteId), operator, requestUrl, requestMethod);
//记录日志
testPlanModuleLogService.saveDeleteLog(deleteModule, currentUser,requestUrl,requestMethod);
testPlanModuleLogService.saveDeleteLog(deleteModule, operator, requestUrl, requestMethod);
}
}
public void deleteModule(List<String> deleteIds) {
public void deleteModule(List<String> deleteIds, String operator, String requestUrl, String requestMethod) {
if (CollectionUtils.isEmpty(deleteIds)) {
return;
}
extTestPlanModuleMapper.deleteByIds(deleteIds);
//todo:删除测试计划
TestPlanBatchProcessRequest request = new TestPlanBatchProcessRequest();
request.setModuleIds(deleteIds);
request.setSelectAll(true);
testPlanService.delete(request, operator, requestUrl, requestMethod);
List<String> childrenIds = extTestPlanModuleMapper.selectChildrenIdsByParentIds(deleteIds);
if (CollectionUtils.isNotEmpty(childrenIds)) {
deleteModule(childrenIds);
deleteModule(childrenIds, operator, requestUrl, requestMethod);
}
}
@ -227,7 +234,7 @@ public class TestPlanModuleService extends ModuleTreeService implements CleanupP
public void deleteResources(String projectId) {
List<String> fileModuleIdList = extTestPlanModuleMapper.selectIdsByProjectId(projectId);
if (CollectionUtils.isNotEmpty(fileModuleIdList)) {
this.deleteModule(fileModuleIdList);
this.deleteModule(fileModuleIdList, "SCHEDULE", "none", "none");
}
}
@ -247,4 +254,7 @@ public class TestPlanModuleService extends ModuleTreeService implements CleanupP
}
}
public String getNameById(String id) {
return extTestPlanModuleMapper.selectNameById(id);
}
}

View File

@ -1,39 +0,0 @@
package io.metersphere.plan.service;
import io.metersphere.plan.domain.TestPlanPrincipal;
import io.metersphere.plan.mapper.TestPlanPrincipalMapper;
import jakarta.annotation.Resource;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Transactional(rollbackFor = Exception.class)
public class TestPlanPrincipalService {
@Resource
private SqlSessionFactory sqlSessionFactory;
public void batchSave(List<TestPlanPrincipal> testPlanPrincipalList) {
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
TestPlanPrincipalMapper testPlanPrincipalMapper = sqlSession.getMapper(TestPlanPrincipalMapper.class);
try {
int insertIndex = 0;
for (TestPlanPrincipal testPlanPrincipal : testPlanPrincipalList) {
testPlanPrincipalMapper.insert(testPlanPrincipal);
insertIndex++;
if (insertIndex % 50 == 0) {
sqlSession.flushStatements();
}
}
sqlSession.flushStatements();
} finally {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
}
}

View File

@ -1,39 +1,49 @@
package io.metersphere.plan.service;
import io.metersphere.plan.domain.*;
import io.metersphere.plan.dto.TestPlanDTO;
import io.metersphere.plan.domain.TestPlan;
import io.metersphere.plan.domain.TestPlanConfig;
import io.metersphere.plan.domain.TestPlanExample;
import io.metersphere.plan.dto.TestPlanQueryConditions;
import io.metersphere.plan.dto.request.TestPlanBatchProcessRequest;
import io.metersphere.plan.dto.request.TestPlanCreateRequest;
import io.metersphere.plan.dto.response.TestPlanResponse;
import io.metersphere.plan.mapper.ExtTestPlanMapper;
import io.metersphere.plan.mapper.TestPlanConfigMapper;
import io.metersphere.plan.mapper.TestPlanMapper;
import io.metersphere.sdk.constants.ApplicationNumScope;
import io.metersphere.sdk.constants.ModuleConstants;
import io.metersphere.sdk.constants.TestPlanConstants;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.domain.TestPlanModuleExample;
import io.metersphere.system.mapper.TestPlanModuleMapper;
import io.metersphere.system.uid.IDGenerator;
import io.metersphere.system.uid.NumGenerator;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
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.validation.annotation.Validated;
import java.util.ArrayList;
import java.util.List;
@Service
@Transactional(rollbackFor = Exception.class)
public class TestPlanService {
private static final long MAX_TEST_PLAN_SIZE = 999;
@Resource
private TestPlanMapper testPlanMapper;
@Resource
private ExtTestPlanMapper extTestPlanMapper;
@Resource
private TestPlanConfigMapper testPlanConfigMapper;
@Resource
private TestPlanLogService testPlanLogService;
@Resource
private TestPlanModuleMapper testPlanModuleMapper;
@Resource
private TestPlanConfigService testPlanConfigService;
@Resource
private TestPlanPrincipalService testPlanPrincipalService;
@Resource
private TestPlanFollowerService testPlanFollowerService;
@Resource
@ -47,103 +57,134 @@ public class TestPlanService {
@Resource
private TestPlanFunctionCaseService testPlanFunctionCaseService;
public TestPlanDTO add(@NotNull TestPlanDTO testPlanCreateRequest) {
if (StringUtils.equals(testPlanCreateRequest.getParentId(), testPlanCreateRequest.getId())) {
throw new MSException("The parent test plan cannot be the same as the current test plan!");
public void checkModule(String moduleId) {
if (!StringUtils.equals(moduleId, ModuleConstants.DEFAULT_NODE_ID)) {
TestPlanModuleExample example = new TestPlanModuleExample();
example.createCriteria().andIdEqualTo(moduleId);
if (testPlanModuleMapper.countByExample(example) == 0) {
throw new MSException("module.not.exist");
}
}
}
if (StringUtils.isBlank(testPlanCreateRequest.getId())) {
testPlanCreateRequest.setId(IDGenerator.nextStr());
}
testPlanCreateRequest.setCreateTime(System.currentTimeMillis());
testPlanCreateRequest.setUpdateTime(System.currentTimeMillis());
public String add(TestPlanCreateRequest testPlanCreateRequest, String operator, String requestUrl, String requestMethod) {
//检查模块的合法性
this.checkModule(testPlanCreateRequest.getModuleId());
TestPlan testPlan = new TestPlan();
BeanUtils.copyBean(testPlan, testPlanCreateRequest);
testPlanMapper.insert(testPlan);
TestPlan createTestPlan = new TestPlan();
BeanUtils.copyBean(createTestPlan, testPlanCreateRequest);
this.validateTestPlan(createTestPlan);
createTestPlan.setId(IDGenerator.nextStr());
long operateTime = System.currentTimeMillis();
createTestPlan.setNum(NumGenerator.nextNum(testPlanCreateRequest.getProjectId(), ApplicationNumScope.TEST_PLAN));
createTestPlan.setCreateUser(operator);
createTestPlan.setUpdateUser(operator);
createTestPlan.setCreateTime(operateTime);
createTestPlan.setUpdateTime(operateTime);
createTestPlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_PREPARED);
createTestPlan.setType(TestPlanConstants.TEST_PLAN_TYPE_PLAN);
testPlanMapper.insert(createTestPlan);
TestPlanConfig testPlanConfig = new TestPlanConfig();
testPlanConfig.setTestPlanId(testPlan.getId());
testPlanConfig.setTestPlanId(createTestPlan.getId());
testPlanConfig.setAutomaticStatusUpdate(testPlanCreateRequest.isAutomaticStatusUpdate());
testPlanConfig.setRepeatCase(testPlanCreateRequest.isRepeatCase());
testPlanConfig.setPassThreshold(testPlanCreateRequest.getPassThreshold());
testPlanConfigMapper.insert(testPlanConfig);
if (CollectionUtils.isNotEmpty(testPlanCreateRequest.getFollowers())) {
List<TestPlanFollower> testPlanFollowerList = new ArrayList<>();
for (String follower : testPlanCreateRequest.getFollowers()) {
TestPlanFollower testPlanFollower = new TestPlanFollower();
testPlanFollower.setTestPlanId(testPlan.getId());
testPlanFollower.setUserId(follower);
testPlanFollowerList.add(testPlanFollower);
}
testPlanFollowerService.batchSave(testPlanFollowerList);
}
testPlanLogService.saveAddLog(createTestPlan, operator, requestUrl, requestMethod);
if (CollectionUtils.isNotEmpty(testPlanCreateRequest.getPrincipals())) {
List<TestPlanPrincipal> testPlanPrincipalList = new ArrayList<>();
for (String principal : testPlanCreateRequest.getPrincipals()) {
TestPlanPrincipal testPlanPrincipal = new TestPlanPrincipal();
testPlanPrincipal.setTestPlanId(testPlan.getId());
testPlanPrincipal.setUserId(principal);
testPlanPrincipalList.add(testPlanPrincipal);
}
testPlanPrincipalService.batchSave(testPlanPrincipalList);
}
return testPlanCreateRequest;
return createTestPlan.getId();
}
public void batchDelete(List<String> idList) {
private void validateTestPlan(TestPlan testPlan) {
if (StringUtils.isBlank(testPlan.getName())) {
throw new MSException(Translator.get("test_plan.name.not_blank"));
}
TestPlanExample example = new TestPlanExample();
example.createCriteria().andIdIn(idList);
testPlanMapper.deleteByExample(example);
if (StringUtils.isBlank(testPlan.getId())) {
this.cascadeDelete(idList);
TestPlanExample.Criteria criteria = example.createCriteria();
//测试计划第一层的数据还不能超过1000个
criteria.andGroupIdEqualTo(TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID);
if (testPlanMapper.countByExample(example) >= MAX_TEST_PLAN_SIZE) {
throw new MSException(Translator.getWithArgs("test_plan.too_many", MAX_TEST_PLAN_SIZE));
}
example.clear();
example.createCriteria().andNameEqualTo(testPlan.getName()).andProjectIdEqualTo(testPlan.getProjectId());
if (testPlanMapper.countByExample(example) > 0) {
throw new MSException(Translator.get("test_plan.name.exist") + ":" + testPlan.getName());
}
} else {
example.createCriteria().andNameEqualTo(testPlan.getName()).andProjectIdEqualTo(testPlan.getProjectId()).andIdNotEqualTo(testPlan.getId());
if (testPlanMapper.countByExample(example) > 0) {
throw new MSException(Translator.get("test_plan.name.exist") + ":" + testPlan.getName());
}
}
}
public void delete(@NotBlank String id) {
public void delete(String id, String operator, String requestUrl, String requestMethod) {
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(id);
testPlanMapper.deleteByPrimaryKey(id);
//级联删除
this.cascadeDeleteTestPlan(id);
TestPlanExample example = new TestPlanExample();
example.createCriteria().andIdEqualTo(id);
testPlanMapper.deleteByExample(example);
this.cascadeDelete(id);
example.createCriteria().andGroupIdEqualTo(id);
List<TestPlan> testPlanItemList = testPlanMapper.selectByExample(example);
testPlanItemList.forEach(item -> this.cascadeDeleteTestPlan(item.getId()));
//记录日志
testPlanLogService.saveDeleteLog(testPlan, testPlanItemList, operator, requestUrl, requestMethod);
}
public void deleteByParentId(String parentTestPlanId) {
List<String> childrenTestPlanIdList = extTestPlanMapper.selectByParentId(parentTestPlanId);
if (CollectionUtils.isNotEmpty(childrenTestPlanIdList)) {
this.batchDelete(childrenTestPlanIdList);
public void delete(TestPlanBatchProcessRequest request, String operator, String requestUrl, String requestMethod) {
List<String> deleteIdList = request.getSelectIds();
if (request.isSelectAll()) {
TestPlanQueryConditions testPlanQueryConditions = new TestPlanQueryConditions(request.getModuleIds(), request.getProjectId(), request.getCondition());
testPlanQueryConditions.setHiddenIds(request.getExcludeIds());
deleteIdList = extTestPlanMapper.selectIdByConditions(testPlanQueryConditions);
}
deleteIdList.forEach(testPlanId -> {
this.delete(testPlanId, operator, requestUrl, requestMethod);
});
}
@Validated
public void deleteBatchByParentId(List<String> parentTestPlanId) {
List<String> childrenTestPlanIdList = extTestPlanMapper.selectByParentIdList(parentTestPlanId);
if (CollectionUtils.isNotEmpty(childrenTestPlanIdList)) {
this.batchDelete(childrenTestPlanIdList);
}
}
private void cascadeDelete(String id) {
//删除子计划
this.deleteByParentId(id);
//删除测试计划以及其他的级联数据
private void cascadeDeleteTestPlan(String testPlanId) {
testPlanMapper.deleteByPrimaryKey(testPlanId);
//删除当前计划对应的资源
this.testPlanConfigService.delete(id);
this.testPlanFunctionCaseService.deleteByTestPlanId(id);
this.testPlanApiCaseService.deleteByTestPlanId(id);
this.testPlanApiScenarioService.deleteByTestPlanId(id);
this.testPlanUiScenarioService.deleteByTestPlanId(id);
this.testPlanLoadCaseService.deleteByTestPlanId(id);
/*
todo
this.testPlanConfigService.delete(testPlanId);
this.testPlanFunctionCaseService.deleteByTestPlanId(testPlanId);
this.testPlanApiCaseService.deleteByTestPlanId(testPlanId);
this.testPlanApiScenarioService.deleteByTestPlanId(testPlanId);
this.testPlanUiScenarioService.deleteByTestPlanId(testPlanId);
this.testPlanLoadCaseService.deleteByTestPlanId(testPlanId);
删除计划的关注者
删除计划报告
删除计划定时任务
*/
}
private void cascadeDelete(List<String> idList) {
//删除子计划
this.deleteBatchByParentId(idList);
//删除当前计划对应的资源
this.testPlanConfigService.deleteBatch(idList);
this.testPlanFunctionCaseService.deleteBatchByTestPlanId(idList);
this.testPlanApiCaseService.deleteBatchByTestPlanId(idList);
this.testPlanApiScenarioService.deleteBatchByTestPlanId(idList);
this.testPlanUiScenarioService.deleteBatchByTestPlanId(idList);
this.testPlanLoadCaseService.deleteBatchByTestPlanId(idList);
public TestPlan getById(String id) {
return testPlanMapper.selectByPrimaryKey(id);
}
public TestPlanResponse getCount(String id) {
TestPlanResponse response = new TestPlanResponse();
response.setId(id);
/*
todo 统计测试进度通过率用例数Bug数量这些比较慢的查询是否需要另开接口查询)
Q:测试计划组需要查询这些数据吗
*/
response.setFunctionalCaseCount(0);
response.setApiCaseCount(0);
response.setApiScenarioCount(0);
response.setPassRate("3.14%");
response.setTestProgress("15.92%");
return response;
}
}

View File

@ -54,25 +54,29 @@
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!-- 模型对象 -->
<javaModelGenerator targetPackage="io.metersphere.system.domain"
<javaModelGenerator targetPackage="io.metersphere.plan.domain"
targetProject="../../framework/domain/src/main/java">
<property name="enableSubPackages" value="true"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- XML映射文件 -->
<sqlMapGenerator targetPackage="io.metersphere.system.mapper"
<sqlMapGenerator targetPackage="io.metersphere.plan.mapper"
targetProject="../../framework/domain/src/main/java">
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<!-- 接口 -->
<javaClientGenerator type="XMLMAPPER" targetPackage="io.metersphere.system.mapper"
<javaClientGenerator type="XMLMAPPER" targetPackage="io.metersphere.plan.mapper"
targetProject="../../framework/domain/src/main/java">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<!--要生成的数据库表 -->
<table tableName="test_plan_module"/>
<!-- <table tableName="test_plan_module"/>-->
<table tableName="test_plan">
<columnOverride column="tags" javaType="java.util.List&lt;String&gt;" jdbcType="VARCHAR"
typeHandler="io.metersphere.handler.ListTypeHandler"/>
</table>
<!-- <table tableName="test_plan_config"/>-->
<!-- 要忽略的字段-->
<!-- <table tableName="test_case">
<ignoreColumn column="follow_people"/>

View File

@ -1,6 +1,12 @@
package io.metersphere.plan.controller;
import io.metersphere.plan.domain.TestPlan;
import io.metersphere.plan.dto.request.TestPlanBatchProcessRequest;
import io.metersphere.plan.dto.request.TestPlanCreateRequest;
import io.metersphere.plan.dto.request.TestPlanTableRequest;
import io.metersphere.plan.dto.response.TestPlanResponse;
import io.metersphere.plan.service.TestPlanModuleService;
import io.metersphere.plan.service.TestPlanTestService;
import io.metersphere.plan.utils.TestPlanUtils;
import io.metersphere.project.domain.Project;
import io.metersphere.project.dto.filemanagement.request.FileModuleCreateRequest;
@ -8,6 +14,7 @@ import io.metersphere.project.dto.filemanagement.request.FileModuleUpdateRequest
import io.metersphere.sdk.constants.ModuleConstants;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.constants.SessionConstants;
import io.metersphere.sdk.constants.TestPlanConstants;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.handler.ResultHolder;
@ -21,8 +28,9 @@ import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.mapper.TestPlanModuleMapper;
import io.metersphere.system.service.CommonProjectService;
import io.metersphere.system.uid.IDGenerator;
import io.metersphere.system.utils.CheckLogModel;
import io.metersphere.system.utils.Pager;
import jakarta.annotation.Resource;
import lombok.Data;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.*;
@ -34,12 +42,23 @@ import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* 1-10: 测试计划模块的增
* 11-20测试计划的增
* 21-90
* ·测试计划相关资源的处理功能用例接口场景缺陷以及预留的性能和UI
* ·测试计划关注
* ·测试计划定时任务
* 91-100测试计划模块的移动测试计划的移动企业版是否需要些暂定
* 101往后测试计划的删除测试计划模块的删除
*/
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@AutoConfigureMockMvc
@ -55,14 +74,30 @@ public class TestPlanTests extends BaseTest {
@Resource
private TestPlanModuleService testPlanModuleService;
@Resource
private TestPlanTestService testPlanTestService;
private static final List<CheckLogModel> LOG_CHECK_LIST = new ArrayList<>();
//测试计划模块的url
private static final String URL_GET_MODULE_TREE = "/test-plan/module/tree/%s";
private static final String URL_GET_MODULE_DELETE = "/test-plan/module/delete/%s";
private static final String URL_POST_MODULE_ADD = "/test-plan/module/add";
private static final String URL_POST_MODULE_UPDATE = "/test-plan/module/update";
private static final String URL_POST_MODULE_MOVE = "/test-plan/module/move";
//测试计划url
private static final String URL_GET_TEST_PLAN_COUNT = "/test-plan/getCount/%s";
private static final String URL_GET_TEST_PLAN_DELETE = "/test-plan/delete/%s";
private static final String URL_POST_TEST_PLAN_PAGE = "/test-plan/page";
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_UPDATE = "/test-plan/update";
private static final String URL_POST_TEST_PLAN_BATCH_DELETE = "/test-plan/batch-delete";
private static String groupTestPlanId7 = null;
private static String groupTestPlanId15 = null;
@BeforeEach
public void initTestData() {
//文件管理专用项目
@ -91,24 +126,22 @@ public class TestPlanTests extends BaseTest {
}
Assertions.assertTrue(hasNode);
/*
todo 查询测试计划列表
FileMetadataTableRequest request = new FileMetadataTableRequest() {{
this.setCurrent(1);
this.setPageSize(10);
this.setProjectId(project.getId());
}};
MvcResult pageResult = this.requestPostWithOkAndReturn(FileManagementRequestUtils.URL_FILE_PAGE, request);
String returnData = pageResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class);
Pager<List<FileInformationResponse>> result = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), Pager.class);
//返回值的页码和当前页码相同
Assertions.assertEquals(result.getCurrent(), request.getCurrent());
//返回的数据量不超过规定要返回的数据量相同
Assertions.assertTrue(JSON.parseArray(JSON.toJSONString(result.getList())).size() <= request.getPageSize());
*/
//查询测试计划列表
TestPlanTableRequest testPlanTableRequest = new TestPlanTableRequest();
testPlanTableRequest.setProjectId(project.getId());
MvcResult pageResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_PAGE, testPlanTableRequest);
String returnData = pageResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class);
Pager<Object> result = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), Pager.class);
//返回值的页码和当前页码相同
Assertions.assertEquals(result.getCurrent(), testPlanTableRequest.getCurrent());
//返回的数据量不超过规定要返回的数据量相同
Assertions.assertTrue(JSON.parseArray(JSON.toJSONString(result.getList())).size() <= testPlanTableRequest.getPageSize());
//判断权限
this.requestGetPermissionTest(PermissionConstants.TEST_PLAN_MODULE_READ, String.format(URL_GET_MODULE_TREE, this.DEFAULT_PROJECT_ID));
this.requestGetPermissionTest(PermissionConstants.TEST_PLAN_MODULE_READ, String.format(URL_GET_MODULE_TREE, DEFAULT_PROJECT_ID));
testPlanTableRequest.setProjectId(DEFAULT_PROJECT_ID);
this.requestPostPermissionTest(PermissionConstants.TEST_PLAN_READ, URL_POST_TEST_PLAN_PAGE, testPlanTableRequest);
}
@Test
@ -258,7 +291,7 @@ public class TestPlanTests extends BaseTest {
);
/**
/*
测试能否正常做200个节点
*/
String parentId = null;
@ -339,7 +372,7 @@ public class TestPlanTests extends BaseTest {
}
@Test
@Order(4)
@Order(3)
public void updateModuleTest() throws Exception {
if (CollectionUtils.isEmpty(preliminaryTreeNodes)) {
this.addModuleTest();
@ -389,11 +422,253 @@ public class TestPlanTests extends BaseTest {
}
/*
80以后是文件模块的移动和删除
*/
@Test
@Order(80)
@Order(11)
public void testPlanAddTest() throws Exception {
this.preliminaryData();
BaseTreeNode a1Node = TestPlanUtils.getNodeByName(preliminaryTreeNodes, "a1");
BaseTreeNode a2Node = TestPlanUtils.getNodeByName(preliminaryTreeNodes, "a2");
BaseTreeNode a3Node = TestPlanUtils.getNodeByName(preliminaryTreeNodes, "a3");
BaseTreeNode a1a1Node = TestPlanUtils.getNodeByName(preliminaryTreeNodes, "a1-a1");
BaseTreeNode a1b1Node = TestPlanUtils.getNodeByName(preliminaryTreeNodes, "a1-b1");
assert a1Node != null & a2Node != null & a3Node != null & a1a1Node != null & a1b1Node != null;
TestPlanCreateRequest request = new TestPlanCreateRequest();
request.setProjectId(project.getId());
for (int i = 0; i < 999; i++) {
String moduleId;
if (i < 50) {
moduleId = a1Node.getId();
} else if (i < 100) {
moduleId = a2Node.getId();
request.setPlannedStartTime(System.currentTimeMillis());
request.setPlannedEndTime(System.currentTimeMillis() + 20000);
} else if (i < 150) {
moduleId = a3Node.getId();
request.setRepeatCase(true);
request.setAutomaticStatusUpdate(true);
} else if (i < 200) {
moduleId = a1a1Node.getId();
request.setPassThreshold((double) i / 3);
request.setDescription("test plan desc " + i);
} else {
moduleId = a1b1Node.getId();
}
//添加测试计划
request.setName("testPlan_" + i);
request.setModuleId(moduleId);
MvcResult mvcResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_ADD, request);
String returnStr = mvcResult.getResponse().getContentAsString();
ResultHolder holder = JSON.parseObject(returnStr, ResultHolder.class);
String returnId = holder.getData().toString();
Assertions.assertNotNull(returnId);
//选择安东尼巅峰期球衣号码为标志该测试计划将改为测试计划组并用于后续的测试用例相关操作
if (i == 7) {
groupTestPlanId7 = returnId;
} else if (i == 15) {
groupTestPlanId15 = returnId;
}
//操作日志检查
LOG_CHECK_LIST.add(
new CheckLogModel(returnId, OperationLogType.ADD, URL_POST_TEST_PLAN_ADD)
);
//部分请求的参数初始化
request.setPlannedEndTime(null);
request.setPlannedStartTime(null);
request.setRepeatCase(false);
request.setAutomaticStatusUpdate(false);
request.setPassThreshold(100);
request.setDescription(null);
}
/*
抽查
testPlan_13没有设置计划开始时间没有设置重复添加用例和自动更新状态阈值为100描述为空
testPlan_53检查是否设置了计划开始结束时间
testPlan_123是否设置了重复添加用例和自动更新状态
testPlan_173的阈值是否不等于100描述不会为空
*/
testPlanTestService.checkTestPlanByAddTest();
//测试继续创建10个
for (int i = 0; i < 10; i++) {
request.setName("testPlan_1000_" + i);
this.requestPost(URL_POST_TEST_PLAN_ADD, request).andExpect(status().is5xxServerError());
}
/*
反例
1.参数校验 name为空
2.module_id不存在
3.group_id
3.1 group_id不存在
3.2 group_id对应的测试计划type不是group
4.参数校验passThreshold大于100
*/
request.setName(null);
this.requestPost(URL_POST_TEST_PLAN_ADD, request).andExpect(status().isBadRequest());
request.setName(IDGenerator.nextStr());
request.setModuleId(IDGenerator.nextStr());
this.requestPost(URL_POST_TEST_PLAN_ADD, request).andExpect(status().is5xxServerError());
request.setModuleId(a1Node.getId());
request.setGroupId(IDGenerator.nextStr());
this.requestPost(URL_POST_TEST_PLAN_ADD, request).andExpect(status().is5xxServerError());
request.setGroupId(groupTestPlanId7);
this.requestPost(URL_POST_TEST_PLAN_ADD, request).andExpect(status().is5xxServerError());
request.setGroupId(TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID);
request.setPassThreshold(100.111);
this.requestPost(URL_POST_TEST_PLAN_ADD, request).andExpect(status().isBadRequest());
//修改一个测试计划的type为group创建子测试计划x-pack功能
testPlanTestService.updateTestPlanTypeToGroup(new String[]{groupTestPlanId7, groupTestPlanId15});
//测试权限
request.setProjectId(DEFAULT_PROJECT_ID);
request.setPassThreshold(100);
this.requestPostPermissionTest(PermissionConstants.TEST_PLAN_READ_ADD, URL_POST_TEST_PLAN_ADD, request);
}
@Test
@Order(12)
public void testPlanPageCountTest() throws Exception {
TestPlanTableRequest testPlanTableRequest = new TestPlanTableRequest();
testPlanTableRequest.setProjectId(project.getId());
MvcResult moduleCountResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_MODULE_COUNT, testPlanTableRequest);
String moduleCountReturnData = moduleCountResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
Map<String, Object> moduleCountMap = JSON.parseObject(JSON.toJSONString(JSON.parseObject(moduleCountReturnData, ResultHolder.class).getData()), Map.class);
AtomicBoolean testPlanIsEmpty = new AtomicBoolean(true);
for (Map.Entry<String, Object> entry : moduleCountMap.entrySet()) {
long value = Long.parseLong(String.valueOf(entry.getValue()));
if (value > 0) {
testPlanIsEmpty.set(false);
}
}
if (testPlanIsEmpty.get()) {
//如果没有数据先创建999条再调用这个方法
this.testPlanAddTest();
this.testPlanPageCountTest();
} else {
BaseTreeNode a1Node = TestPlanUtils.getNodeByName(preliminaryTreeNodes, "a1");
BaseTreeNode a2Node = TestPlanUtils.getNodeByName(preliminaryTreeNodes, "a2");
BaseTreeNode a3Node = TestPlanUtils.getNodeByName(preliminaryTreeNodes, "a3");
BaseTreeNode a1a1Node = TestPlanUtils.getNodeByName(preliminaryTreeNodes, "a1-a1");
BaseTreeNode a1b1Node = TestPlanUtils.getNodeByName(preliminaryTreeNodes, "a1-b1");
assert a1Node != null & a2Node != null & a3Node != null & a1a1Node != null & a1b1Node != null;
//检查每个节点下的数据是否匹配的上父节点的统计会一并添加上子节点的数据
moduleCountMap.forEach((k, v) -> {
if (StringUtils.equals(k, a1Node.getId())) {
Assertions.assertEquals(v, 50 + 50 + 799);
} else if (StringUtils.equals(k, a2Node.getId())) {
Assertions.assertEquals(v, 50);
} else if (StringUtils.equals(k, a3Node.getId())) {
Assertions.assertEquals(v, 50);
} else if (StringUtils.equals(k, a1a1Node.getId())) {
Assertions.assertEquals(v, 50);
} else if (StringUtils.equals(k, a1b1Node.getId())) {
Assertions.assertEquals(v, 799);
}
});
//查询测试计划列表
MvcResult pageResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_PAGE, testPlanTableRequest);
String returnData = pageResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class);
Pager<Object> result = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), Pager.class);
//返回值的页码和当前页码相同
Assertions.assertEquals(result.getCurrent(), testPlanTableRequest.getCurrent());
//返回的数据量不超过规定要返回的数据量相同
Assertions.assertTrue(JSON.parseArray(JSON.toJSONString(result.getList())).size() <= testPlanTableRequest.getPageSize());
Assertions.assertEquals(result.getTotal(), 999);
//查询详情
List<TestPlanResponse> testPlanResponseList = JSON.parseArray(JSON.toJSONString(result.getList()), TestPlanResponse.class);
for (TestPlanResponse response : testPlanResponseList) {
this.requestGetWithOk(String.format(URL_GET_TEST_PLAN_COUNT, response.getId()));
}
//指定模块ID查询 (查询count时不会因为选择了模块而更改了总量
testPlanTableRequest.setModuleIds(Arrays.asList(a1Node.getId(), a1a1Node.getId(), a1b1Node.getId()));
moduleCountResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_MODULE_COUNT, testPlanTableRequest);
moduleCountReturnData = moduleCountResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
moduleCountMap = JSON.parseObject(JSON.toJSONString(JSON.parseObject(moduleCountReturnData, ResultHolder.class).getData()), Map.class);
moduleCountMap.forEach((k, v) -> {
if (StringUtils.equals(k, a1Node.getId())) {
Assertions.assertEquals(v, 50 + 50 + 799);
} else if (StringUtils.equals(k, a2Node.getId())) {
Assertions.assertEquals(v, 50);
} else if (StringUtils.equals(k, a3Node.getId())) {
Assertions.assertEquals(v, 50);
} else if (StringUtils.equals(k, a1a1Node.getId())) {
Assertions.assertEquals(v, 50);
} else if (StringUtils.equals(k, a1b1Node.getId())) {
Assertions.assertEquals(v, 799);
}
});
pageResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_PAGE, testPlanTableRequest);
returnData = pageResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
resultHolder = JSON.parseObject(returnData, ResultHolder.class);
result = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), Pager.class);
//返回值的页码和当前页码相同
Assertions.assertEquals(result.getCurrent(), testPlanTableRequest.getCurrent());
//返回的数据量不超过规定要返回的数据量相同
Assertions.assertTrue(JSON.parseArray(JSON.toJSONString(result.getList())).size() <= testPlanTableRequest.getPageSize());
Assertions.assertEquals(result.getTotal(), 899);
//测试根据名称模糊查询 Plan_2 预期结果 a1Node下有11条testPlan_2,testPlan_20~testPlan_29), a1b1Node下有100条testPlan_200~testPlan_299
testPlanTableRequest.setModuleIds(null);
testPlanTableRequest.setKeyword("Plan_2");
moduleCountResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_MODULE_COUNT, testPlanTableRequest);
moduleCountReturnData = moduleCountResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
moduleCountMap = JSON.parseObject(JSON.toJSONString(JSON.parseObject(moduleCountReturnData, ResultHolder.class).getData()), Map.class);
moduleCountMap.forEach((k, v) -> {
if (StringUtils.equals(k, a1Node.getId())) {
Assertions.assertEquals(v, 11 + 100);
} else if (StringUtils.equals(k, a2Node.getId())) {
Assertions.assertEquals(v, 0);
} else if (StringUtils.equals(k, a3Node.getId())) {
Assertions.assertEquals(v, 0);
} else if (StringUtils.equals(k, a1a1Node.getId())) {
Assertions.assertEquals(v, 0);
} else if (StringUtils.equals(k, a1b1Node.getId())) {
Assertions.assertEquals(v, 100);
}
});
pageResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_PAGE, testPlanTableRequest);
returnData = pageResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
resultHolder = JSON.parseObject(returnData, ResultHolder.class);
result = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), Pager.class);
//返回值的页码和当前页码相同
Assertions.assertEquals(result.getCurrent(), testPlanTableRequest.getCurrent());
//返回的数据量不超过规定要返回的数据量相同
Assertions.assertTrue(JSON.parseArray(JSON.toJSONString(result.getList())).size() <= testPlanTableRequest.getPageSize());
Assertions.assertEquals(result.getTotal(), 111);
//反例参数校验项目ID不存在
testPlanTableRequest.setProjectId(null);
this.requestPost(URL_POST_TEST_PLAN_MODULE_COUNT, testPlanTableRequest).andExpect(status().isBadRequest());
this.requestPost(URL_POST_TEST_PLAN_PAGE, testPlanTableRequest).andExpect(status().isBadRequest());
//测试权限
testPlanTableRequest.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_PAGE, testPlanTableRequest);
}
}
@Test
@Order(91)
public void moveTest() throws Exception {
this.preliminaryData();
/*
@ -418,7 +693,7 @@ public class TestPlanTests extends BaseTest {
BaseTreeNode a3Node = TestPlanUtils.getNodeByName(preliminaryTreeNodes, "a3");
BaseTreeNode a1a1Node = TestPlanUtils.getNodeByName(preliminaryTreeNodes, "a1-a1");
BaseTreeNode a1b1Node = TestPlanUtils.getNodeByName(preliminaryTreeNodes, "a1-b1");
assert a1Node != null & a2Node != null & a3Node != null & a1a1Node != null & a1b1Node != null;
//父节点内移动-移动到首位 a1挪到a3后面
NodeMoveRequest request = new NodeMoveRequest();
{
@ -641,12 +916,71 @@ public class TestPlanTests extends BaseTest {
}
@Test
@Order(90)
public void deleteModuleTestSuccess() throws Exception {
@Order(101)
public void deleteTestPlanTest() throws Exception {
if (StringUtils.isEmpty(groupTestPlanId7)) {
this.testPlanAddTest();
}
//根据id删除 删除 第61这1个)
List<TestPlan> testPlanList = testPlanTestService.selectByProjectIdAndNames(project.getId(),
new String[]{"testPlan_61"});
this.requestGet(String.format(URL_GET_TEST_PLAN_DELETE, testPlanList.get(0).getId())).andExpect(status().isOk());
Assertions.assertTrue(testPlanTestService.checkDataCount(project.getId(), 999 - 1));
//根据id删除 删除 第610-619这11个)
testPlanList = testPlanTestService.selectByProjectIdAndNames(project.getId(),
new String[]{"testPlan_61", "testPlan_610", "testPlan_611", "testPlan_612", "testPlan_613", "testPlan_614", "testPlan_615", "testPlan_616", "testPlan_617", "testPlan_618", "testPlan_619"});
TestPlanBatchProcessRequest request = new TestPlanBatchProcessRequest();
request.setProjectId(project.getId());
request.setSelectIds(testPlanList.stream().map(TestPlan::getId).collect(Collectors.toList()));
this.requestPostWithOk(URL_POST_TEST_PLAN_BATCH_DELETE, request);
Assertions.assertTrue(testPlanTestService.checkDataCount(project.getId(), 999 - 1 - 10));
// 根据查询条件删除 删除plan_2)这一部分
request = new TestPlanBatchProcessRequest();
request.setProjectId(project.getId());
request.setSelectAll(true);
request.getCondition().setKeyword("plan_2");
this.requestPostWithOk(URL_POST_TEST_PLAN_BATCH_DELETE, request);
Assertions.assertTrue(testPlanTestService.checkDataCount(project.getId(), 999 - (1 + 10) - (1 + 10 + 100)));
//批量删除的数据中包含group7这个用户组
request = new TestPlanBatchProcessRequest();
request.setSelectIds(Collections.singletonList(groupTestPlanId7));
request.setProjectId(project.getId());
this.requestPostWithOk(URL_POST_TEST_PLAN_BATCH_DELETE, request);
Assertions.assertTrue(testPlanTestService.checkDataCount(project.getId(), 999 - (1 + 10) - (1 + 10 + 100) - 1));
//根据a1a1Node模快删除
BaseTreeNode a1a1Node = TestPlanUtils.getNodeByName(this.getFileModuleTreeNode(), "a1-a1");
request = new TestPlanBatchProcessRequest();
request.setSelectAll(true);
request.setModuleIds(Arrays.asList(a1a1Node.getId()));
request.setProjectId(project.getId());
this.requestPostWithOk(URL_POST_TEST_PLAN_BATCH_DELETE, request);
Assertions.assertTrue(testPlanTestService.checkDataCount(project.getId(), 999 - (1 + 10) - (1 + 10 + 100) - 1 - 50));
//根据 a1b1Node模块以及planSty这个条件删除应当删除0条数据量不会变化
BaseTreeNode a1b1Node = TestPlanUtils.getNodeByName(this.getFileModuleTreeNode(), "a1-b1");
request = new TestPlanBatchProcessRequest();
request.setSelectAll(true);
request.setModuleIds(Arrays.asList(a1b1Node.getId()));
request.getCondition().setKeyword("planSty");
request.setProjectId(project.getId());
this.requestPostWithOk(URL_POST_TEST_PLAN_BATCH_DELETE, request);
Assertions.assertTrue(testPlanTestService.checkDataCount(project.getId(), 999 - (1 + 10) - (1 + 10 + 100) - 1 - 50));
}
@Test
@Order(102)
public void deleteModuleTest() throws Exception {
this.preliminaryData();
// 删除没有文件的节点a1-b1-c1 检查是否级联删除根节点
BaseTreeNode a1b1Node = TestPlanUtils.getNodeByName(this.getFileModuleTreeNode(), "a1-b1");
assert a1b1Node != null;
this.requestGetWithOk(String.format(URL_GET_MODULE_DELETE, a1b1Node.getId()));
this.checkModuleIsEmpty(a1b1Node.getId());
LOG_CHECK_LIST.add(
@ -655,6 +989,7 @@ public class TestPlanTests extends BaseTest {
// 删除有文件的节点 a1-a1 检查是否级联删除根节点
BaseTreeNode a1a1Node = TestPlanUtils.getNodeByName(this.getFileModuleTreeNode(), "a1-a1");
assert a1a1Node != null;
this.requestGetWithOk(String.format(URL_GET_MODULE_DELETE, a1a1Node.getId()));
this.checkModuleIsEmpty(a1a1Node.getId());
LOG_CHECK_LIST.add(
@ -667,7 +1002,7 @@ public class TestPlanTests extends BaseTest {
this.requestGetWithOk(String.format(URL_GET_MODULE_DELETE, ModuleConstants.DEFAULT_NODE_ID));
//service层判断测试删除空集合
testPlanModuleService.deleteModule(new ArrayList<>());
testPlanModuleService.deleteModule(new ArrayList<>(), null, null, null);
//service层判断测试删除项目
testPlanModuleService.deleteResources(project.getId());
@ -684,12 +1019,9 @@ public class TestPlanTests extends BaseTest {
example = new TestPlanModuleExample();
example.createCriteria().andIdEqualTo(id);
Assertions.assertEquals(testPlanModuleMapper.countByExample(example), 0);
/*
todo 该模块下已无测试计划
FileMetadataExample metadataExample = new FileMetadataExample();
metadataExample.createCriteria().andModuleIdEqualTo(id);
Assertions.assertEquals(testPlanModuleMapper.countByExample(metadataExample), 0);
*/
// 该模块下已无测试计划
Assertions.assertEquals(testPlanTestService.countByModuleId(id), 0);
}
@ -759,7 +1091,7 @@ public class TestPlanTests extends BaseTest {
@Test
@Order(100)
@Order(110)
public void testLog() throws Exception {
Thread.sleep(5000);
for (CheckLogModel checkLogModel : LOG_CHECK_LIST) {
@ -771,24 +1103,3 @@ public class TestPlanTests extends BaseTest {
}
}
}
@Data
class CheckLogModel {
private String resourceId;
private OperationLogType operationType;
private String url;
public CheckLogModel(String resourceId, OperationLogType operationType, String url) {
this.resourceId = resourceId;
this.operationType = operationType;
this.url = getLogUrl(url);
}
private String getLogUrl(String url) {
if (StringUtils.endsWith(url, "/%s")) {
return StringUtils.substring(url, 0, url.length() - 3);
} else {
return url;
}
}
}

View File

@ -0,0 +1,100 @@
package io.metersphere.plan.service;
import io.metersphere.plan.domain.TestPlan;
import io.metersphere.plan.domain.TestPlanConfig;
import io.metersphere.plan.domain.TestPlanExample;
import io.metersphere.plan.mapper.TestPlanConfigMapper;
import io.metersphere.plan.mapper.TestPlanMapper;
import io.metersphere.sdk.constants.TestPlanConstants;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Assertions;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class TestPlanTestService {
@Resource
private TestPlanMapper testPlanMapper;
@Resource
private TestPlanConfigMapper testPlanConfigMapper;
public void checkTestPlanByAddTest() {
/*
抽查
testPlan_13没有设置计划开始时间没有设置重复添加用例和自动更新状态阈值为100描述为空
testPlan_53检查是否设置了计划开始结束时间
testPlan_123是否设置了重复添加用例和自动更新状态
testPlan_173的阈值是否不等于100描述不会为空
*/
TestPlanExample testPlanExample = new TestPlanExample();
testPlanExample.createCriteria().andNameEqualTo("testPlan_13");
TestPlan testPlan = testPlanMapper.selectByExample(testPlanExample).get(0);
TestPlanConfig testPlanConfig = testPlanConfigMapper.selectByPrimaryKey(testPlan.getId());
Assertions.assertNull(testPlan.getPlannedStartTime());
Assertions.assertNull(testPlan.getPlannedEndTime());
Assertions.assertEquals(testPlanConfig.getPassThreshold(), 100);
Assertions.assertEquals(testPlanConfig.getRepeatCase(), false);
Assertions.assertEquals(testPlanConfig.getAutomaticStatusUpdate(), false);
Assertions.assertNull(testPlan.getDescription());
testPlanExample.clear();
testPlanExample.createCriteria().andNameEqualTo("testPlan_53");
testPlan = testPlanMapper.selectByExample(testPlanExample).get(0);
testPlanConfig = testPlanConfigMapper.selectByPrimaryKey(testPlan.getId());
Assertions.assertNotNull(testPlan.getPlannedStartTime());
Assertions.assertNotNull(testPlan.getPlannedEndTime());
Assertions.assertEquals(testPlanConfig.getPassThreshold(), 100);
Assertions.assertEquals(testPlanConfig.getRepeatCase(), false);
Assertions.assertEquals(testPlanConfig.getAutomaticStatusUpdate(), false);
Assertions.assertNull(testPlan.getDescription());
testPlanExample.clear();
testPlanExample.createCriteria().andNameEqualTo("testPlan_123");
testPlan = testPlanMapper.selectByExample(testPlanExample).get(0);
testPlanConfig = testPlanConfigMapper.selectByPrimaryKey(testPlan.getId());
Assertions.assertNull(testPlan.getPlannedStartTime());
Assertions.assertNull(testPlan.getPlannedEndTime());
Assertions.assertEquals(testPlanConfig.getPassThreshold(), 100);
Assertions.assertEquals(testPlanConfig.getRepeatCase(), true);
Assertions.assertEquals(testPlanConfig.getAutomaticStatusUpdate(), true);
Assertions.assertNull(testPlan.getDescription());
testPlanExample.clear();
testPlanExample.createCriteria().andNameEqualTo("testPlan_173");
testPlan = testPlanMapper.selectByExample(testPlanExample).get(0);
testPlanConfig = testPlanConfigMapper.selectByPrimaryKey(testPlan.getId());
Assertions.assertNull(testPlan.getPlannedStartTime());
Assertions.assertNull(testPlan.getPlannedEndTime());
Assertions.assertNotEquals(testPlanConfig.getPassThreshold(), 100);
Assertions.assertEquals(testPlanConfig.getRepeatCase(), false);
Assertions.assertEquals(testPlanConfig.getAutomaticStatusUpdate(), false);
Assertions.assertNotNull(testPlan.getDescription());
}
public void updateTestPlanTypeToGroup(String[] testPlanIds) {
TestPlanExample testPlanExample = new TestPlanExample();
testPlanExample.createCriteria().andIdIn(List.of(testPlanIds));
TestPlan testPlan = new TestPlan();
testPlan.setType(TestPlanConstants.TEST_PLAN_TYPE_GROUP);
testPlanMapper.updateByExampleSelective(testPlan, testPlanExample);
}
public List<TestPlan> selectByProjectIdAndNames(String projectId, String[] strings) {
TestPlanExample testPlanExample = new TestPlanExample();
testPlanExample.createCriteria().andProjectIdEqualTo(projectId).andNameIn(List.of(strings));
return testPlanMapper.selectByExample(testPlanExample);
}
public boolean checkDataCount(String projectId, int finalCount) {
TestPlanExample testPlanExample = new TestPlanExample();
testPlanExample.createCriteria().andProjectIdEqualTo(projectId);
return testPlanMapper.countByExample(testPlanExample) == finalCount;
}
public long countByModuleId(String id) {
TestPlanExample testPlanExample = new TestPlanExample();
testPlanExample.createCriteria().andModuleIdEqualTo(id);
return testPlanMapper.countByExample(testPlanExample);
}
}