feat(测试计划): 保存测试规划功能

This commit is contained in:
song-cc-rock 2024-06-04 10:37:48 +08:00 committed by 刘瑞斌
parent eb23e4b212
commit 2019042649
15 changed files with 636 additions and 335 deletions

View File

@ -1,132 +1,132 @@
package io.metersphere.plan.domain; package io.metersphere.plan.domain;
import io.metersphere.validation.groups.Created; import io.metersphere.validation.groups.Created;
import io.metersphere.validation.groups.Updated; import io.metersphere.validation.groups.Updated;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import lombok.Data; import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@Data @Data
public class TestPlanAllocation implements Serializable { public class TestPlanAllocation implements Serializable {
@Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan_allocation.id.not_blank}", groups = {Updated.class}) @NotBlank(message = "{test_plan_allocation.id.not_blank}", groups = {Updated.class})
@Size(min = 1, max = 50, message = "{test_plan_allocation.id.length_range}", groups = {Created.class, Updated.class}) @Size(min = 1, max = 50, message = "{test_plan_allocation.id.length_range}", groups = {Created.class, Updated.class})
private String id; private String id;
@Schema(description = "测试计划ID", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "测试计划ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan_allocation.test_plan_id.not_blank}", groups = {Created.class}) @NotBlank(message = "{test_plan_allocation.id.not_blank}", groups = {Updated.class})
@Size(min = 1, max = 50, message = "{test_plan_allocation.test_plan_id.length_range}", groups = {Created.class, Updated.class}) @Size(min = 1, max = 50, message = "{test_plan_allocation.test_plan_id.length_range}", groups = {Created.class, Updated.class})
private String testPlanId; private String testPlanId;
@Schema(description = "资源池ID", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "资源池ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan_allocation.test_resource_pool_id.not_blank}", groups = {Created.class}) @NotBlank(message = "{test_plan_allocation.test_resource_pool_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{test_plan_allocation.test_resource_pool_id.length_range}", groups = {Created.class, Updated.class}) @Size(min = 1, max = 50, message = "{test_plan_allocation.test_resource_pool_id.length_range}", groups = {Created.class, Updated.class})
private String testResourcePoolId; private String testResourcePoolId;
@Schema(description = "是否失败重试", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "是否失败重试", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "{test_plan_allocation.retry_on_fail.not_blank}", groups = {Created.class}) @NotNull(message = "{test_plan_allocation.retry_on_fail.not_blank}", groups = {Created.class})
private Boolean retryOnFail; private Boolean retryOnFail;
@Schema(description = "失败重试类型(步骤/场景)", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "失败重试类型(步骤/场景)", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan_allocation.retry_type.not_blank}", groups = {Created.class}) @NotBlank(message = "{test_plan_allocation.retry_type.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{test_plan_allocation.retry_type.length_range}", groups = {Created.class, Updated.class}) @Size(min = 1, max = 50, message = "{test_plan_allocation.retry_type.length_range}", groups = {Created.class, Updated.class})
private String retryType; private String retryType;
@Schema(description = "失败重试次数", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "失败重试次数", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "{test_plan_allocation.retry_times.not_blank}", groups = {Created.class}) @NotNull(message = "{test_plan_allocation.retry_times.not_blank}", groups = {Created.class})
private Integer retryTimes; private Integer retryTimes;
@Schema(description = "失败重试间隔(单位: ms)", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "失败重试间隔(单位: ms)", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "{test_plan_allocation.retry_interval.not_blank}", groups = {Created.class}) @NotNull(message = "{test_plan_allocation.retry_interval.not_blank}", groups = {Created.class})
private Integer retryInterval; private Integer retryInterval;
@Schema(description = "是否失败停止", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "是否失败停止", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "{test_plan_allocation.stop_on_fail.not_blank}", groups = {Created.class}) @NotNull(message = "{test_plan_allocation.stop_on_fail.not_blank}", groups = {Created.class})
private Boolean stopOnFail; private Boolean stopOnFail;
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public enum Column { public enum Column {
id("id", "id", "VARCHAR", false), id("id", "id", "VARCHAR", false),
testPlanId("test_plan_id", "testPlanId", "VARCHAR", false), testPlanId("test_plan_id", "testPlanId", "VARCHAR", false),
testResourcePoolId("test_resource_pool_id", "testResourcePoolId", "VARCHAR", false), testResourcePoolId("test_resource_pool_id", "testResourcePoolId", "VARCHAR", false),
retryOnFail("retry_on_fail", "retryOnFail", "BIT", false), retryOnFail("retry_on_fail", "retryOnFail", "BIT", false),
retryType("retry_type", "retryType", "VARCHAR", false), retryType("retry_type", "retryType", "VARCHAR", false),
retryTimes("retry_times", "retryTimes", "INTEGER", false), retryTimes("retry_times", "retryTimes", "INTEGER", false),
retryInterval("retry_interval", "retryInterval", "INTEGER", false), retryInterval("retry_interval", "retryInterval", "INTEGER", false),
stopOnFail("stop_on_fail", "stopOnFail", "BIT", false); stopOnFail("stop_on_fail", "stopOnFail", "BIT", false);
private static final String BEGINNING_DELIMITER = "`"; private static final String BEGINNING_DELIMITER = "`";
private static final String ENDING_DELIMITER = "`"; private static final String ENDING_DELIMITER = "`";
private final String column; private final String column;
private final boolean isColumnNameDelimited; private final boolean isColumnNameDelimited;
private final String javaProperty; private final String javaProperty;
private final String jdbcType; private final String jdbcType;
public String value() { public String value() {
return this.column; return this.column;
} }
public String getValue() { public String getValue() {
return this.column; return this.column;
} }
public String getJavaProperty() { public String getJavaProperty() {
return this.javaProperty; return this.javaProperty;
} }
public String getJdbcType() { public String getJdbcType() {
return this.jdbcType; return this.jdbcType;
} }
Column(String column, String javaProperty, String jdbcType, boolean isColumnNameDelimited) { Column(String column, String javaProperty, String jdbcType, boolean isColumnNameDelimited) {
this.column = column; this.column = column;
this.javaProperty = javaProperty; this.javaProperty = javaProperty;
this.jdbcType = jdbcType; this.jdbcType = jdbcType;
this.isColumnNameDelimited = isColumnNameDelimited; this.isColumnNameDelimited = isColumnNameDelimited;
} }
public String desc() { public String desc() {
return this.getEscapedColumnName() + " DESC"; return this.getEscapedColumnName() + " DESC";
} }
public String asc() { public String asc() {
return this.getEscapedColumnName() + " ASC"; return this.getEscapedColumnName() + " ASC";
} }
public static Column[] excludes(Column ... excludes) { public static Column[] excludes(Column ... excludes) {
ArrayList<Column> columns = new ArrayList<>(Arrays.asList(Column.values())); ArrayList<Column> columns = new ArrayList<>(Arrays.asList(Column.values()));
if (excludes != null && excludes.length > 0) { if (excludes != null && excludes.length > 0) {
columns.removeAll(new ArrayList<>(Arrays.asList(excludes))); columns.removeAll(new ArrayList<>(Arrays.asList(excludes)));
} }
return columns.toArray(new Column[]{}); return columns.toArray(new Column[]{});
} }
public static Column[] all() { public static Column[] all() {
return Column.values(); return Column.values();
} }
public String getEscapedColumnName() { public String getEscapedColumnName() {
if (this.isColumnNameDelimited) { if (this.isColumnNameDelimited) {
return new StringBuilder().append(BEGINNING_DELIMITER).append(this.column).append(ENDING_DELIMITER).toString(); return new StringBuilder().append(BEGINNING_DELIMITER).append(this.column).append(ENDING_DELIMITER).toString();
} else { } else {
return this.column; return this.column;
} }
} }
public String getAliasedEscapedColumnName() { public String getAliasedEscapedColumnName() {
return this.getEscapedColumnName(); return this.getEscapedColumnName();
} }
} }
} }

View File

@ -19,13 +19,16 @@ alter table test_plan
ALTER TABLE test_plan_config DROP `test_planning`; ALTER TABLE test_plan_config DROP `test_planning`;
-- 修改计划报告详情表字段 -- 修改计划报告详情表字段
UPDATE test_plan_report_summary SET bug_count = 0 WHERE bug_count IS NULL;
ALTER TABLE test_plan_report_summary MODIFY `bug_count` BIGINT NOT NULL DEFAULT 0 COMMENT '缺陷数量'; ALTER TABLE test_plan_report_summary MODIFY `bug_count` BIGINT NOT NULL DEFAULT 0 COMMENT '缺陷数量';
ALTER TABLE test_plan_report_summary DROP `report_count`; ALTER TABLE test_plan_report_summary DROP `report_count`;
-- 修改计划报告功能用例表字段 -- 修改计划报告功能用例表字段
UPDATE test_plan_report_function_case SET function_case_bug_count = 0 WHERE function_case_bug_count IS NULL;
ALTER TABLE test_plan_report_function_case MODIFY `function_case_bug_count` BIGINT NOT NULL DEFAULT 0 COMMENT '功能用例关联缺陷数'; ALTER TABLE test_plan_report_function_case MODIFY `function_case_bug_count` BIGINT NOT NULL DEFAULT 0 COMMENT '功能用例关联缺陷数';
-- 修改计划报告缺陷表字段 -- 修改计划报告缺陷表字段
UPDATE test_plan_report_bug SET bug_case_count = 0 WHERE bug_case_count IS NULL;
ALTER TABLE test_plan_report_bug MODIFY `bug_case_count` BIGINT NOT NULL DEFAULT 0 COMMENT '缺陷用例数'; ALTER TABLE test_plan_report_bug MODIFY `bug_case_count` BIGINT NOT NULL DEFAULT 0 COMMENT '缺陷用例数';
-- 修改测试计划关联接口表字段 -- 修改测试计划关联接口表字段

View File

@ -104,11 +104,11 @@ test_plan.batch.log={0}测试计划
test_plan_report_not_exist=测试计划报告不存在 test_plan_report_not_exist=测试计划报告不存在
test_plan_report_id.not_blank=测试计划报告id不能为空 test_plan_report_id.not_blank=测试计划报告id不能为空
test_plan_report_name.not_blank=测试计划报告名称不能为空 test_plan_report_name.not_blank=测试计划报告名称不能为空
run_functional_case=执行功能用例
test_plan_not_exist=测试计划不存在 test_plan_not_exist=测试计划不存在
test_plan.report_id.not_blank=测试计划报告ID不能为空 test_plan.report_id.not_blank=测试计划报告ID不能为空
test_plan.report.share_id.not_blank=测试计划报告分享ID不能为空 test_plan.report.share_id.not_blank=测试计划报告分享ID不能为空
no_plan_to_archive=没有可归档的计划/计划组 no_plan_to_archive=没有可归档的计划/计划组
test_plan.is.archived=测试计划已归档 test_plan.is.archived=测试计划已归档
test_plan_module_already_exists=同名模块已存在 test_plan_module_already_exists=同名模块已存在
test_plan_report_name_length_range=报告名称长度过长 test_plan_report_name_length_range=报告名称长度过长
test_plan_allocation_type_param_error=测试集所属分类参数错误

View File

@ -111,4 +111,5 @@ test_plan.report.share_id.not_blank=The test plan report share ID cannot be empt
no_plan_to_archive=No plans/plan groups to archive no_plan_to_archive=No plans/plan groups to archive
test_plan.is.archived=Test plan has been archived test_plan.is.archived=Test plan has been archived
test_plan_module_already_exists=The module with the same name already exists test_plan_module_already_exists=The module with the same name already exists
test_plan_report_name_length_range=The report name is too long test_plan_report_name_length_range=The report name is too long
test_plan_allocation_type_param_error=The parameter of the allocation type is not correct

View File

@ -111,4 +111,5 @@ test_plan.report.share_id.not_blank=测试计划报告分享ID不能为空
no_plan_to_archive=没有可归档的计划/计划组 no_plan_to_archive=没有可归档的计划/计划组
test_plan.is.archived=测试计划已归档 test_plan.is.archived=测试计划已归档
test_plan_module_already_exists=同名模块已存在 test_plan_module_already_exists=同名模块已存在
test_plan_report_name_length_range=报告名称长度过长 test_plan_report_name_length_range=报告名称长度过长
test_plan_allocation_type_param_error=测试集所属分类参数错误

View File

@ -111,4 +111,5 @@ test_plan.report.share_id.not_blank=測試計劃報告分享ID不能爲空
no_plan_to_archive=沒有可歸檔的計劃/計劃組 no_plan_to_archive=沒有可歸檔的計劃/計劃組
test_plan.is.archived=測試計劃已歸檔 test_plan.is.archived=測試計劃已歸檔
test_plan_module_already_exists=同名模塊已存在 test_plan_module_already_exists=同名模塊已存在
test_plan_report_name_length_range=报告名称长度过长 test_plan_report_name_length_range=报告名称长度过长
test_plan_allocation_type_param_error=測試集所屬分類參數錯誤

View File

@ -1,61 +1,63 @@
package io.metersphere.functional.provider; package io.metersphere.functional.provider;
import io.metersphere.dto.BaseCaseCustomFieldDTO; import io.metersphere.dto.BaseCaseCustomFieldDTO;
import io.metersphere.dto.TestCaseProviderDTO; import io.metersphere.dto.TestCaseProviderDTO;
import io.metersphere.functional.dto.FunctionalCaseCustomFieldDTO; import io.metersphere.functional.dto.FunctionalCaseCustomFieldDTO;
import io.metersphere.functional.mapper.ExtFunctionalCaseMapper; import io.metersphere.functional.mapper.ExtFunctionalCaseMapper;
import io.metersphere.functional.service.FunctionalCaseService; import io.metersphere.functional.service.FunctionalCaseService;
import io.metersphere.provider.BaseAssociateCaseProvider; import io.metersphere.provider.BaseAssociateCaseProvider;
import io.metersphere.request.AssociateOtherCaseRequest; import io.metersphere.request.AssociateOtherCaseRequest;
import io.metersphere.request.TestCasePageProviderRequest; import io.metersphere.request.TestCasePageProviderRequest;
import io.metersphere.sdk.util.BeanUtils; import io.metersphere.sdk.util.BeanUtils;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@Service("FUNCTIONAL") @Service("FUNCTIONAL")
public class AssociateFunctionalProvider implements BaseAssociateCaseProvider { public class AssociateFunctionalProvider implements BaseAssociateCaseProvider {
@Resource @Resource
private FunctionalCaseService functionalCaseService; private FunctionalCaseService functionalCaseService;
@Resource @Resource
private ExtFunctionalCaseMapper extFunctionalCaseMapper; private ExtFunctionalCaseMapper extFunctionalCaseMapper;
@Override @Override
public List<TestCaseProviderDTO> listUnRelatedTestCaseList(TestCasePageProviderRequest testCasePageProviderRequest) { public List<TestCaseProviderDTO> listUnRelatedTestCaseList(TestCasePageProviderRequest testCasePageProviderRequest) {
List<TestCaseProviderDTO> functionalCases = extFunctionalCaseMapper.listUnRelatedCaseWithBug(testCasePageProviderRequest, false, testCasePageProviderRequest.getSortString()); List<TestCaseProviderDTO> functionalCases = extFunctionalCaseMapper.listUnRelatedCaseWithBug(testCasePageProviderRequest, false, testCasePageProviderRequest.getSortString());
if (CollectionUtils.isEmpty(functionalCases)) { if (CollectionUtils.isEmpty(functionalCases)) {
return new ArrayList<>(); return new ArrayList<>();
} }
List<String> ids = functionalCases.stream().map(TestCaseProviderDTO::getId).toList(); List<String> ids = functionalCases.stream().map(TestCaseProviderDTO::getId).toList();
Map<String, List<FunctionalCaseCustomFieldDTO>> caseCustomFiledMap = functionalCaseService.getCaseCustomFiledMap(ids, testCasePageProviderRequest.getProjectId()); Map<String, List<FunctionalCaseCustomFieldDTO>> caseCustomFiledMap = functionalCaseService.getCaseCustomFiledMap(ids, testCasePageProviderRequest.getProjectId());
functionalCases.forEach(functionalCase -> { functionalCases.forEach(functionalCase -> {
List<FunctionalCaseCustomFieldDTO> customFields = caseCustomFiledMap.get(functionalCase.getId()); List<FunctionalCaseCustomFieldDTO> customFields = caseCustomFiledMap.get(functionalCase.getId());
List<BaseCaseCustomFieldDTO> customs = new ArrayList<>(); if (CollectionUtils.isNotEmpty(customFields)) {
for (FunctionalCaseCustomFieldDTO customField : customFields) { List<BaseCaseCustomFieldDTO> customs = new ArrayList<>();
BaseCaseCustomFieldDTO baseCaseCustomFieldDTO = new BaseCaseCustomFieldDTO(); for (FunctionalCaseCustomFieldDTO customField : customFields) {
BeanUtils.copyBean(baseCaseCustomFieldDTO, customField); BaseCaseCustomFieldDTO baseCaseCustomFieldDTO = new BaseCaseCustomFieldDTO();
customs.add(baseCaseCustomFieldDTO); BeanUtils.copyBean(baseCaseCustomFieldDTO, customField);
} customs.add(baseCaseCustomFieldDTO);
functionalCase.setCustomFields(customs); }
}); functionalCase.setCustomFields(customs);
return functionalCases; }
} });
return functionalCases;
@Override }
public List<String> getRelatedIdsByParam(AssociateOtherCaseRequest request, boolean deleted) {
if (request.isSelectAll()) { @Override
List<String> relatedIds = extFunctionalCaseMapper.getSelectIdsByAssociateParam(request, deleted); public List<String> getRelatedIdsByParam(AssociateOtherCaseRequest request, boolean deleted) {
if (CollectionUtils.isNotEmpty(request.getExcludeIds())) { if (request.isSelectAll()) {
relatedIds = relatedIds.stream().filter(id -> !request.getExcludeIds().contains(id)).toList(); List<String> relatedIds = extFunctionalCaseMapper.getSelectIdsByAssociateParam(request, deleted);
} if (CollectionUtils.isNotEmpty(request.getExcludeIds())) {
return relatedIds; relatedIds = relatedIds.stream().filter(id -> !request.getExcludeIds().contains(id)).toList();
} else { }
return request.getSelectIds(); return relatedIds;
} } else {
} return request.getSelectIds();
} }
}
}

View File

@ -0,0 +1,24 @@
package io.metersphere.plan.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
public class TestPlanAllocationTypeDTO {
@Schema(description = "测试集类型ID")
private String id;
@Schema(description = "测试集名称", requiredMode = Schema.RequiredMode.REQUIRED)
private String name;
@Schema(description = "测试集类型", allowableValues = {"FUNCTIONAL", "API", "SCENARIO"}, requiredMode = Schema.RequiredMode.REQUIRED)
private String type;
@Schema(description = "执行方式", allowableValues = {"SERIAL-串行", "PARALLEL-并行"}, requiredMode = Schema.RequiredMode.REQUIRED)
private String executeMethod;
@Schema(description = "位置, 从1开始递增的整数即可", requiredMode = Schema.RequiredMode.REQUIRED)
private Long pos;
}

View File

@ -0,0 +1,29 @@
package io.metersphere.plan.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
public class TestPlanCollectionInitDTO {
@Schema(description = "测试集节点ID")
private String id;
@Schema(description = "所属测试集类型ID, 类型ID空时传递具体测试集类型名称即可", requiredMode = Schema.RequiredMode.REQUIRED)
private String testCollectionTypeId;
@Schema(description = "测试集名称", requiredMode = Schema.RequiredMode.REQUIRED)
private String name;
@Schema(description = "执行方式", allowableValues = {"SERIAL-串行", "PARALLEL-并行"}, requiredMode = Schema.RequiredMode.REQUIRED)
private String executeMethod;
@Schema(description = "是否使用环境组", requiredMode = Schema.RequiredMode.REQUIRED)
private Boolean grouped;
@Schema(description = "环境ID/环境组ID, 根据是否环境组来传递相应的值", requiredMode = Schema.RequiredMode.REQUIRED)
private String environmentId;
@Schema(description = "位置, 从1开始递增的整数即可", requiredMode = Schema.RequiredMode.REQUIRED)
private Long pos;
}

View File

@ -0,0 +1,27 @@
package io.metersphere.plan.dto.request;
import io.metersphere.plan.domain.TestPlanAllocation;
import io.metersphere.plan.dto.TestPlanAllocationTypeDTO;
import io.metersphere.plan.dto.TestPlanCollectionInitDTO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
* 规划创建请求参数-脑图使用
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class TestPlanAllocationCreateRequest {
@Schema(description = "规划节点(分类/类型-第二级)")
private List<TestPlanAllocationTypeDTO> typeNodes;
@Schema(description = "规划节点(功能集-第三级)")
private List<TestPlanCollectionInitDTO> collectionNodes;
@Schema(description = "规划配置")
private TestPlanAllocation config;
}

View File

@ -1,78 +1,81 @@
package io.metersphere.plan.dto.request; package io.metersphere.plan.dto.request;
import io.metersphere.sdk.constants.ModuleConstants; import io.metersphere.sdk.constants.ModuleConstants;
import io.metersphere.sdk.constants.TestPlanConstants; import io.metersphere.sdk.constants.TestPlanConstants;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min; import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import lombok.Data; import lombok.Data;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
@Data @Data
public class TestPlanCreateRequest { public class TestPlanCreateRequest {
@Schema(description = "测试计划所属项目", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "测试计划所属项目", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan.project_id.not_blank}") @NotBlank(message = "{test_plan.project_id.not_blank}")
@Size(min = 1, max = 50, message = "{test_plan.project_id.length_range}") @Size(min = 1, max = 50, message = "{test_plan.project_id.length_range}")
private String projectId; private String projectId;
@Schema(description = "测试计划组ID;测试计划要改为树结构。最上层的为NONE其余则是父节点ID") @Schema(description = "测试计划组ID;测试计划要改为树结构。最上层的为NONE其余则是父节点ID")
@Size(min = 1, max = 50, message = "{test_plan.parent_id.length_range}") @Size(min = 1, max = 50, message = "{test_plan.parent_id.length_range}")
private String groupId = TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID; private String groupId = TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID;
@Schema(description = "测试计划名称", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "测试计划名称", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan.name.not_blank}") @NotBlank(message = "{test_plan.name.not_blank}")
@Size(min = 1, max = 255, message = "{test_plan.name.length_range}") @Size(min = 1, max = 255, message = "{test_plan.name.length_range}")
private String name; private String name;
@Schema(description = "测试计划模块ID") @Schema(description = "测试计划模块ID")
@Size(min = 1, max = 50, message = "{test_plan.parent_id.length_range}") @Size(min = 1, max = 50, message = "{test_plan.parent_id.length_range}")
private String moduleId = ModuleConstants.DEFAULT_NODE_ID; private String moduleId = ModuleConstants.DEFAULT_NODE_ID;
@Schema(description = "计划开始时间") @Schema(description = "计划开始时间")
private Long plannedStartTime; private Long plannedStartTime;
@Schema(description = "计划结束时间") @Schema(description = "计划结束时间")
private Long plannedEndTime; private Long plannedEndTime;
@Schema(description = "标签") @Schema(description = "标签")
private LinkedHashSet< private LinkedHashSet<
@NotBlank @NotBlank
String> tags; String> tags;
@Schema(description = "描述") @Schema(description = "描述")
private String description; private String description;
@Schema(description = "是否开启测试规划", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "是否开启测试规划", requiredMode = Schema.RequiredMode.REQUIRED)
private boolean testPlanning; private boolean testPlanning;
@Schema(description = "是否自定更新功能用例状态", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "是否自定更新功能用例状态", requiredMode = Schema.RequiredMode.REQUIRED)
private boolean automaticStatusUpdate; private boolean automaticStatusUpdate;
@Schema(description = "是否允许重复添加用例", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "是否允许重复添加用例", requiredMode = Schema.RequiredMode.REQUIRED)
private boolean repeatCase; private boolean repeatCase;
@Schema(description = "测试计划通过阈值;0-100", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "测试计划通过阈值;0-100", requiredMode = Schema.RequiredMode.REQUIRED)
@Max(value = 100, message = "{test_plan.pass_threshold.max}") @Max(value = 100, message = "{test_plan.pass_threshold.max}")
@Min(value = 0) @Min(value = 0)
private double passThreshold = 100; private double passThreshold = 100;
@Schema(description = "测试计划类型",allowableValues ={"TEST_PLAN", "GROUP"}, requiredMode = Schema.RequiredMode.REQUIRED ) @Schema(description = "测试计划类型",allowableValues ={"TEST_PLAN", "GROUP"}, requiredMode = Schema.RequiredMode.REQUIRED )
private String type = TestPlanConstants.TEST_PLAN_TYPE_PLAN; private String type = TestPlanConstants.TEST_PLAN_TYPE_PLAN;
public List<String> getTags() { public List<String> getTags() {
return tags == null ? null : new ArrayList<>(tags); return tags == null ? null : new ArrayList<>(tags);
} }
public boolean isGroupOption() { public boolean isGroupOption() {
return StringUtils.equals(this.type, TestPlanConstants.TEST_PLAN_TYPE_GROUP) || !StringUtils.equals(this.groupId, TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID); return StringUtils.equals(this.type, TestPlanConstants.TEST_PLAN_TYPE_GROUP) || !StringUtils.equals(this.groupId, TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID);
} }
@Schema(description = "查询用例的条件") @Schema(description = "查询用例的条件")
private BaseAssociateCaseRequest baseAssociateCaseRequest; private BaseAssociateCaseRequest baseAssociateCaseRequest;
}
@Schema(description = "测试规划请求参数")
private TestPlanAllocationCreateRequest allocationRequest;
}

View File

@ -1,56 +1,58 @@
package io.metersphere.plan.dto.request; package io.metersphere.plan.dto.request;
import io.metersphere.sdk.constants.ModuleConstants; import io.metersphere.sdk.constants.ModuleConstants;
import io.metersphere.sdk.constants.TestPlanConstants; import io.metersphere.sdk.constants.TestPlanConstants;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min; import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import lombok.Data; import lombok.Data;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
@Data @Data
public class TestPlanUpdateRequest { public class TestPlanUpdateRequest {
@Schema(description = "测试计划ID") @Schema(description = "测试计划ID")
@NotBlank(message = "{test_plan.id.not_blank}") @NotBlank(message = "{test_plan.id.not_blank}")
private String id; private String id;
@Schema(description = "测试计划名称") @Schema(description = "测试计划名称")
@Size(min = 1, max = 255, message = "{test_plan.name.length_range}") @Size(min = 1, max = 255, message = "{test_plan.name.length_range}")
private String name; private String name;
@Schema(description = "模块ID") @Schema(description = "模块ID")
private String moduleId = ModuleConstants.DEFAULT_NODE_ID; private String moduleId = ModuleConstants.DEFAULT_NODE_ID;
@Schema(description = "标签") @Schema(description = "标签")
private LinkedHashSet<String> tags; private LinkedHashSet<String> tags;
@Schema(description = "计划开始时间") @Schema(description = "计划开始时间")
private Long plannedStartTime; private Long plannedStartTime;
@Schema(description = "计划结束时间") @Schema(description = "计划结束时间")
private Long plannedEndTime; private Long plannedEndTime;
@Schema(description = "描述") @Schema(description = "描述")
private String description; private String description;
@Schema(description = "是否开启测试规划") @Schema(description = "是否开启测试规划")
private Boolean testPlanning; private Boolean testPlanning;
@Schema(description = "是否自定更新功能用例状态") @Schema(description = "是否自定更新功能用例状态")
private Boolean automaticStatusUpdate; private Boolean automaticStatusUpdate;
@Schema(description = "是否允许重复添加用例") @Schema(description = "是否允许重复添加用例")
private Boolean repeatCase; private Boolean repeatCase;
@Schema(description = "测试计划通过阈值;0-100", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "测试计划通过阈值;0-100", requiredMode = Schema.RequiredMode.REQUIRED)
@Max(value = 100) @Max(value = 100)
@Min(value = 0) @Min(value = 0)
private Double passThreshold; private Double passThreshold;
@Schema(description = "测试计划组Id") @Schema(description = "测试计划组Id")
private String testPlanGroupId = TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID; private String testPlanGroupId = TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID;
} @Schema(description = "测试规划请求参数")
private TestPlanAllocationCreateRequest allocationRequest;
}

View File

@ -0,0 +1,14 @@
package io.metersphere.plan.enums;
public enum ExecuteMethod {
/**
* 串行
*/
SERIAL,
/**
* 并行
*/
PARALLEL
}

View File

@ -83,6 +83,7 @@ public class TestPlanService extends TestPlanBaseUtilsService {
private TestPlanSendNoticeService testPlanSendNoticeService; private TestPlanSendNoticeService testPlanSendNoticeService;
@Resource @Resource
private TestPlanCaseExecuteHistoryMapper testPlanCaseExecuteHistoryMapper; private TestPlanCaseExecuteHistoryMapper testPlanCaseExecuteHistoryMapper;
private static final int MAX_TAG_SIZE = 10; private static final int MAX_TAG_SIZE = 10;
/** /**
@ -90,6 +91,8 @@ public class TestPlanService extends TestPlanBaseUtilsService {
*/ */
public TestPlan add(TestPlanCreateRequest testPlanCreateRequest, String operator, String requestUrl, String requestMethod) { public TestPlan add(TestPlanCreateRequest testPlanCreateRequest, String operator, String requestUrl, String requestMethod) {
TestPlan testPlan = savePlanDTO(testPlanCreateRequest, operator, null); TestPlan testPlan = savePlanDTO(testPlanCreateRequest, operator, null);
// 保存规划节点及配置
saveAllocation(testPlanCreateRequest.getAllocationRequest(), operator, testPlan.getId());
testPlanLogService.saveAddLog(testPlan, operator, requestUrl, requestMethod); testPlanLogService.saveAddLog(testPlan, operator, requestUrl, requestMethod);
return testPlan; return testPlan;
} }
@ -152,6 +155,82 @@ public class TestPlanService extends TestPlanBaseUtilsService {
} }
} }
/**
* 保存规划
*
* @param allocationRequest 规划的请求参数
* @param currentUser 当前用户
*/
private void saveAllocation(TestPlanAllocationCreateRequest allocationRequest, String currentUser, String planId) {
// 前置参数校验
checkAllocationParam(allocationRequest);
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
TestPlanAllocationTypeMapper allocationTypeBatchMapper = sqlSession.getMapper(TestPlanAllocationTypeMapper.class);
TestPlanCollectionMapper collectionBatchMapper = sqlSession.getMapper(TestPlanCollectionMapper.class);
// 处理测试集分类
Map<String, String> allocationTypeMap = new HashMap<>();
List<TestPlanAllocationType> addAllocationTypes = new ArrayList<>();
List<TestPlanAllocationType> updateAllocationTypes = new ArrayList<>();
allocationRequest.getTypeNodes().forEach(allocationTypeDTO -> {
TestPlanAllocationType allocationType = new TestPlanAllocationType();
BeanUtils.copyBean(allocationType, allocationTypeDTO);
allocationType.setTestPlanId(planId);
allocationType.setPos(allocationType.getPos() << 6);
if (allocationTypeDTO.getId() == null) {
allocationType.setId(IDGenerator.nextStr());
allocationTypeMap.put(allocationType.getType(), allocationType.getId());
addAllocationTypes.add(allocationType);
} else {
updateAllocationTypes.add(allocationType);
}
});
// 处理测试集
List<TestPlanCollection> addCollections = new ArrayList<>();
List<TestPlanCollection> updateCollections = new ArrayList<>();
if (CollectionUtils.isNotEmpty(allocationRequest.getCollectionNodes())) {
allocationRequest.getCollectionNodes().forEach(collectionNode -> {
TestPlanCollection collection = new TestPlanCollection();
BeanUtils.copyBean(collection, collectionNode);
collection.setTestPlanId(planId);
collection.setPos(collection.getPos() << 6);
if (collection.getId() == null) {
collection.setId(IDGenerator.nextStr());
collection.setTestCollectionTypeId(allocationTypeMap.get(collection.getTestCollectionTypeId()));
collection.setCreateUser(currentUser);
collection.setCreateTime(System.currentTimeMillis());
addCollections.add(collection);
} else {
updateCollections.add(collection);
}
});
}
// 入库 { 测试集分类, 测试集, 规划配置项 }
if (CollectionUtils.isNotEmpty(addAllocationTypes)) {
allocationTypeBatchMapper.batchInsert(addAllocationTypes);
}
if (CollectionUtils.isNotEmpty(updateAllocationTypes)) {
// 仅有三条记录
updateAllocationTypes.forEach(allocationType -> allocationTypeBatchMapper.updateByPrimaryKey(allocationType));
}
if (CollectionUtils.isNotEmpty(addCollections)) {
collectionBatchMapper.batchInsert(addCollections);
}
if (CollectionUtils.isNotEmpty(updateCollections)) {
updateCollections.forEach(collection -> collectionBatchMapper.updateByPrimaryKeySelective(collection));
}
if (allocationRequest.getConfig().getId() == null) {
TestPlanAllocation allocationConfig = allocationRequest.getConfig();
allocationConfig.setId(IDGenerator.nextStr());
allocationConfig.setTestPlanId(planId);
testPlanAllocationMapper.insert(allocationConfig);
} else {
testPlanAllocationMapper.updateByPrimaryKeySelective(allocationRequest.getConfig());
}
sqlSession.flushStatements();
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
/** /**
* 删除测试计划 * 删除测试计划
@ -326,6 +405,8 @@ public class TestPlanService extends TestPlanBaseUtilsService {
testPlanConfig.setPassThreshold(request.getPassThreshold()); testPlanConfig.setPassThreshold(request.getPassThreshold());
testPlanConfigMapper.updateByPrimaryKeySelective(testPlanConfig); testPlanConfigMapper.updateByPrimaryKeySelective(testPlanConfig);
} }
// 保存规划节点及配置
saveAllocation(request.getAllocationRequest(), userId, testPlan.getId());
testPlanLogService.saveUpdateLog(testPlan, testPlanMapper.selectByPrimaryKey(request.getId()), testPlan.getProjectId(), userId, requestUrl, requestMethod); testPlanLogService.saveUpdateLog(testPlan, testPlanMapper.selectByPrimaryKey(request.getId()), testPlan.getProjectId(), userId, requestUrl, requestMethod);
return testPlan; return testPlan;
} }
@ -721,4 +802,10 @@ public class TestPlanService extends TestPlanBaseUtilsService {
return new TestPlanResourceSortResponse(1); return new TestPlanResourceSortResponse(1);
} }
private void checkAllocationParam(TestPlanAllocationCreateRequest request) {
if (CollectionUtils.size(request.getTypeNodes()) != 3) {
throw new MSException(Translator.get("test_plan_allocation_type_param_error"));
}
}
} }

View File

@ -5,12 +5,13 @@ import io.metersphere.api.domain.ApiTestCase;
import io.metersphere.functional.domain.FunctionalCase; import io.metersphere.functional.domain.FunctionalCase;
import io.metersphere.plan.constants.TestPlanResourceConfig; import io.metersphere.plan.constants.TestPlanResourceConfig;
import io.metersphere.plan.domain.*; import io.metersphere.plan.domain.*;
import io.metersphere.plan.dto.TestPlanAllocationTypeDTO;
import io.metersphere.plan.dto.TestPlanCollectionInitDTO;
import io.metersphere.plan.dto.request.*; import io.metersphere.plan.dto.request.*;
import io.metersphere.plan.dto.response.TestPlanResourceSortResponse; import io.metersphere.plan.dto.response.TestPlanResourceSortResponse;
import io.metersphere.plan.dto.response.TestPlanResponse; import io.metersphere.plan.dto.response.TestPlanResponse;
import io.metersphere.plan.mapper.ExtTestPlanMapper; import io.metersphere.plan.enums.ExecuteMethod;
import io.metersphere.plan.mapper.TestPlanMapper; import io.metersphere.plan.mapper.*;
import io.metersphere.plan.mapper.TestPlanReportMapper;
import io.metersphere.plan.service.*; import io.metersphere.plan.service.*;
import io.metersphere.plan.utils.TestPlanTestUtils; import io.metersphere.plan.utils.TestPlanTestUtils;
import io.metersphere.project.domain.Project; import io.metersphere.project.domain.Project;
@ -89,6 +90,12 @@ public class TestPlanTests extends BaseTest {
private CommonProjectService commonProjectService; private CommonProjectService commonProjectService;
@Resource @Resource
private TestPlanTestService testPlanTestService; private TestPlanTestService testPlanTestService;
@Resource
private TestPlanAllocationTypeMapper testPlanAllocationTypeMapper;
@Resource
private TestPlanCollectionMapper testPlanCollectionMapper;
@Resource
private TestPlanAllocationMapper testPlanAllocationMapper;
private static final List<CheckLogModel> LOG_CHECK_LIST = new ArrayList<>(); private static final List<CheckLogModel> LOG_CHECK_LIST = new ArrayList<>();
@ -526,6 +533,7 @@ public class TestPlanTests extends BaseTest {
BaseAssociateCaseRequest associateCaseRequest = new BaseAssociateCaseRequest(); BaseAssociateCaseRequest associateCaseRequest = new BaseAssociateCaseRequest();
request.setBaseAssociateCaseRequest(associateCaseRequest); request.setBaseAssociateCaseRequest(associateCaseRequest);
request.setAllocationRequest(buildAllocationParam());
for (int i = 0; i < 999; i++) { for (int i = 0; i < 999; i++) {
String moduleId; String moduleId;
if (i < 50) { if (i < 50) {
@ -637,6 +645,7 @@ public class TestPlanTests extends BaseTest {
itemRequest.setGroupId(groupTestPlanId7); itemRequest.setGroupId(groupTestPlanId7);
itemRequest.setName("testPlan_group7_" + i); itemRequest.setName("testPlan_group7_" + i);
itemRequest.setBaseAssociateCaseRequest(associateCaseRequest); itemRequest.setBaseAssociateCaseRequest(associateCaseRequest);
itemRequest.setAllocationRequest(buildAllocationParam());
if (i == 0) { if (i == 0) {
//测试项目没有开启测试计划模块时能否使用 //测试项目没有开启测试计划模块时能否使用
testPlanTestService.removeProjectModule(project, PROJECT_MODULE, "testPlan"); testPlanTestService.removeProjectModule(project, PROJECT_MODULE, "testPlan");
@ -947,6 +956,7 @@ public class TestPlanTests extends BaseTest {
//修改名称 //修改名称
TestPlanUpdateRequest updateRequest = testPlanTestService.generateUpdateRequest(testPlan.getId()); TestPlanUpdateRequest updateRequest = testPlanTestService.generateUpdateRequest(testPlan.getId());
updateRequest.setName(IDGenerator.nextStr()); updateRequest.setName(IDGenerator.nextStr());
updateRequest.setAllocationRequest(buildAllocationParam());
//测试项目没有开启测试计划模块时能否使用 //测试项目没有开启测试计划模块时能否使用
testPlanTestService.removeProjectModule(project, PROJECT_MODULE, "testPlan"); testPlanTestService.removeProjectModule(project, PROJECT_MODULE, "testPlan");
@ -965,6 +975,7 @@ public class TestPlanTests extends BaseTest {
//修改回来 //修改回来
updateRequest = testPlanTestService.generateUpdateRequest(testPlan.getId()); updateRequest = testPlanTestService.generateUpdateRequest(testPlan.getId());
updateRequest.setName(testPlan.getName()); updateRequest.setName(testPlan.getName());
updateRequest.setAllocationRequest(buildAllocationParam());
mvcResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_UPDATE, updateRequest); mvcResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_UPDATE, updateRequest);
returnStr = mvcResult.getResponse().getContentAsString(); returnStr = mvcResult.getResponse().getContentAsString();
holder = JSON.parseObject(returnStr, ResultHolder.class); holder = JSON.parseObject(returnStr, ResultHolder.class);
@ -983,6 +994,7 @@ public class TestPlanTests extends BaseTest {
BaseTreeNode a2Node = TestPlanTestUtils.getNodeByName(preliminaryTreeNodes, "a2"); BaseTreeNode a2Node = TestPlanTestUtils.getNodeByName(preliminaryTreeNodes, "a2");
updateRequest = testPlanTestService.generateUpdateRequest(testPlan.getId()); updateRequest = testPlanTestService.generateUpdateRequest(testPlan.getId());
updateRequest.setModuleId(a2Node.getId()); updateRequest.setModuleId(a2Node.getId());
updateRequest.setAllocationRequest(buildAllocationParam());
mvcResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_UPDATE, updateRequest); mvcResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_UPDATE, updateRequest);
returnStr = mvcResult.getResponse().getContentAsString(); returnStr = mvcResult.getResponse().getContentAsString();
holder = JSON.parseObject(returnStr, ResultHolder.class); holder = JSON.parseObject(returnStr, ResultHolder.class);
@ -991,6 +1003,7 @@ public class TestPlanTests extends BaseTest {
testPlanTestService.checkTestPlanUpdateResult(testPlan, testPlanConfig, updateRequest); testPlanTestService.checkTestPlanUpdateResult(testPlan, testPlanConfig, updateRequest);
//修改回来 //修改回来
updateRequest = testPlanTestService.generateUpdateRequest(testPlan.getId()); updateRequest = testPlanTestService.generateUpdateRequest(testPlan.getId());
updateRequest.setAllocationRequest(buildAllocationParam());
updateRequest.setModuleId(testPlan.getModuleId()); updateRequest.setModuleId(testPlan.getModuleId());
mvcResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_UPDATE, updateRequest); mvcResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_UPDATE, updateRequest);
returnStr = mvcResult.getResponse().getContentAsString(); returnStr = mvcResult.getResponse().getContentAsString();
@ -1001,6 +1014,7 @@ public class TestPlanTests extends BaseTest {
//修改标签 //修改标签
updateRequest = testPlanTestService.generateUpdateRequest(testPlan.getId()); updateRequest = testPlanTestService.generateUpdateRequest(testPlan.getId());
updateRequest.setAllocationRequest(buildAllocationParam());
updateRequest.setTags(new LinkedHashSet<>(Arrays.asList("tag1", "tag2", "tag3", "tag3"))); updateRequest.setTags(new LinkedHashSet<>(Arrays.asList("tag1", "tag2", "tag3", "tag3")));
mvcResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_UPDATE, updateRequest); mvcResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_UPDATE, updateRequest);
returnStr = mvcResult.getResponse().getContentAsString(); returnStr = mvcResult.getResponse().getContentAsString();
@ -1012,6 +1026,7 @@ public class TestPlanTests extends BaseTest {
//修改计划开始结束时间 //修改计划开始结束时间
updateRequest = testPlanTestService.generateUpdateRequest(testPlan.getId()); updateRequest = testPlanTestService.generateUpdateRequest(testPlan.getId());
updateRequest.setAllocationRequest(buildAllocationParam());
updateRequest.setPlannedStartTime(System.currentTimeMillis()); updateRequest.setPlannedStartTime(System.currentTimeMillis());
updateRequest.setPlannedEndTime(updateRequest.getPlannedStartTime() - 10000); updateRequest.setPlannedEndTime(updateRequest.getPlannedStartTime() - 10000);
mvcResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_UPDATE, updateRequest); mvcResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_UPDATE, updateRequest);
@ -1024,6 +1039,7 @@ public class TestPlanTests extends BaseTest {
//修改描述 //修改描述
updateRequest = testPlanTestService.generateUpdateRequest(testPlan.getId()); updateRequest = testPlanTestService.generateUpdateRequest(testPlan.getId());
updateRequest.setAllocationRequest(buildAllocationParam());
updateRequest.setDescription("This is desc"); updateRequest.setDescription("This is desc");
mvcResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_UPDATE, updateRequest); mvcResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_UPDATE, updateRequest);
returnStr = mvcResult.getResponse().getContentAsString(); returnStr = mvcResult.getResponse().getContentAsString();
@ -1035,6 +1051,7 @@ public class TestPlanTests extends BaseTest {
//修改配置项 //修改配置项
updateRequest = testPlanTestService.generateUpdateRequest(testPlan.getId()); updateRequest = testPlanTestService.generateUpdateRequest(testPlan.getId());
updateRequest.setAllocationRequest(buildAllocationParam());
updateRequest.setAutomaticStatusUpdate(true); updateRequest.setAutomaticStatusUpdate(true);
updateRequest.setRepeatCase(true); updateRequest.setRepeatCase(true);
updateRequest.setPassThreshold(43.12); updateRequest.setPassThreshold(43.12);
@ -1046,6 +1063,7 @@ public class TestPlanTests extends BaseTest {
testPlanTestService.checkTestPlanUpdateResult(testPlan, testPlanConfig, updateRequest); testPlanTestService.checkTestPlanUpdateResult(testPlan, testPlanConfig, updateRequest);
updateRequest = testPlanTestService.generateUpdateRequest(testPlan.getId()); updateRequest = testPlanTestService.generateUpdateRequest(testPlan.getId());
updateRequest.setAllocationRequest(buildAllocationParam());
updateRequest.setAutomaticStatusUpdate(false); updateRequest.setAutomaticStatusUpdate(false);
updateRequest.setRepeatCase(false); updateRequest.setRepeatCase(false);
updateRequest.setPassThreshold(56.47); updateRequest.setPassThreshold(56.47);
@ -1060,16 +1078,19 @@ public class TestPlanTests extends BaseTest {
//修改a2节点下的数据91,92的所属测试计划组 //修改a2节点下的数据91,92的所属测试计划组
updateRequest = testPlanTestService.generateUpdateRequest(testPlanTestService.selectTestPlanByName("testPlan_91").getId()); updateRequest = testPlanTestService.generateUpdateRequest(testPlanTestService.selectTestPlanByName("testPlan_91").getId());
updateRequest.setAllocationRequest(buildAllocationParam());
updateRequest.setTestPlanGroupId(groupTestPlanId7); updateRequest.setTestPlanGroupId(groupTestPlanId7);
this.requestPostWithOk(URL_POST_TEST_PLAN_UPDATE, updateRequest); this.requestPostWithOk(URL_POST_TEST_PLAN_UPDATE, updateRequest);
a2NodeCount--; a2NodeCount--;
updateRequest = testPlanTestService.generateUpdateRequest(testPlanTestService.selectTestPlanByName("testPlan_92").getId()); updateRequest = testPlanTestService.generateUpdateRequest(testPlanTestService.selectTestPlanByName("testPlan_92").getId());
updateRequest.setAllocationRequest(buildAllocationParam());
updateRequest.setTestPlanGroupId(groupTestPlanId7); updateRequest.setTestPlanGroupId(groupTestPlanId7);
this.requestPostWithOk(URL_POST_TEST_PLAN_UPDATE, updateRequest); this.requestPostWithOk(URL_POST_TEST_PLAN_UPDATE, updateRequest);
a2NodeCount--; a2NodeCount--;
//修改测试计划组信息 //修改测试计划组信息
updateRequest = testPlanTestService.generateUpdateRequest(groupTestPlanId7); updateRequest = testPlanTestService.generateUpdateRequest(groupTestPlanId7);
updateRequest.setAllocationRequest(buildAllocationParam());
updateRequest.setName(IDGenerator.nextStr()); updateRequest.setName(IDGenerator.nextStr());
updateRequest.setDescription("This is desc"); updateRequest.setDescription("This is desc");
updateRequest.setTags(new LinkedHashSet<>(Arrays.asList("tag1", "tag2", "tag3", "tag3"))); updateRequest.setTags(new LinkedHashSet<>(Arrays.asList("tag1", "tag2", "tag3", "tag3")));
@ -1079,6 +1100,7 @@ public class TestPlanTests extends BaseTest {
//什么都不修改 //什么都不修改
updateRequest = testPlanTestService.generateUpdateRequest(testPlan.getId()); updateRequest = testPlanTestService.generateUpdateRequest(testPlan.getId());
updateRequest.setAllocationRequest(buildAllocationParam());
this.requestPostWithOk(URL_POST_TEST_PLAN_UPDATE, updateRequest); this.requestPostWithOk(URL_POST_TEST_PLAN_UPDATE, updateRequest);
//因为有条数据被移动了测试计划组里所以检查一下moduleCount. //因为有条数据被移动了测试计划组里所以检查一下moduleCount.
@ -1838,7 +1860,7 @@ public class TestPlanTests extends BaseTest {
TestPlanCreateRequest request = new TestPlanCreateRequest(); TestPlanCreateRequest request = new TestPlanCreateRequest();
request.setProjectId(project.getId()); request.setProjectId(project.getId());
request.setTestPlanning(false); request.setTestPlanning(false);
request.setAllocationRequest(buildAllocationParam());
BaseAssociateCaseRequest associateCaseRequest = new BaseAssociateCaseRequest(); BaseAssociateCaseRequest associateCaseRequest = new BaseAssociateCaseRequest();
associateCaseRequest.setFunctionalSelectIds(Arrays.asList("wx_fc_1", "wx_fc_2")); associateCaseRequest.setFunctionalSelectIds(Arrays.asList("wx_fc_1", "wx_fc_2"));
request.setBaseAssociateCaseRequest(associateCaseRequest); request.setBaseAssociateCaseRequest(associateCaseRequest);
@ -2045,4 +2067,89 @@ public class TestPlanTests extends BaseTest {
this.requestPostWithOk(URL_TEST_PLAN_BATCH_EDIT, request); this.requestPostWithOk(URL_TEST_PLAN_BATCH_EDIT, request);
} }
@Test
@Order(308)
void testSaveAllocation() throws Exception {
TestPlanCreateRequest createRequest = new TestPlanCreateRequest();
BaseAssociateCaseRequest associateCaseRequest = new BaseAssociateCaseRequest();
createRequest.setBaseAssociateCaseRequest(associateCaseRequest);
createRequest.setTestPlanning(true);
createRequest.setProjectId(project.getId());
createRequest.setName("测试一下关联");
createRequest.setPlannedEndTime(null);
createRequest.setPlannedStartTime(null);
createRequest.setRepeatCase(false);
createRequest.setAutomaticStatusUpdate(false);
createRequest.setPassThreshold(100);
createRequest.setDescription(null);
createRequest.setType(TestPlanConstants.TEST_PLAN_TYPE_PLAN);
createRequest.setAllocationRequest(buildAllocationParam());
MvcResult mvcResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_ADD, createRequest);
String sortData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder sortHolder = JSON.parseObject(sortData, ResultHolder.class);
TestPlan testPlan = JSON.parseObject(JSON.toJSONString(sortHolder.getData()), TestPlan.class);
TestPlanAllocationCreateRequest updateRequest = buildAllocationUpdateParam(testPlan.getId());
createRequest.setAllocationRequest(updateRequest);
this.requestPostWithOk(URL_POST_TEST_PLAN_ADD, createRequest);
TestPlanAllocationCreateRequest createRequest1 = buildAllocationParam();
createRequest1.setCollectionNodes(null);
createRequest.setAllocationRequest(createRequest1);
this.requestPostWithOk(URL_POST_TEST_PLAN_ADD, createRequest);
}
private TestPlanAllocationCreateRequest buildAllocationParam() {
TestPlanAllocationCreateRequest request = new TestPlanAllocationCreateRequest();
TestPlanAllocationTypeDTO functionalType = new TestPlanAllocationTypeDTO();
functionalType.setType(CaseType.FUNCTIONAL_CASE.getKey());
functionalType.setName("功能用例");
functionalType.setPos(1L);
functionalType.setExecuteMethod(ExecuteMethod.SERIAL.name());
request.setTypeNodes(List.of(functionalType, functionalType, functionalType));
TestPlanCollectionInitDTO collection = new TestPlanCollectionInitDTO();
collection.setName("默认测试集");
collection.setTestCollectionTypeId(CaseType.FUNCTIONAL_CASE.getKey());
collection.setExecuteMethod(ExecuteMethod.PARALLEL.name());
collection.setGrouped(false);
collection.setEnvironmentId(IDGenerator.nextStr());
collection.setPos(1L);
request.setCollectionNodes(List.of(collection));
TestPlanAllocation allocation = new TestPlanAllocation();
allocation.setTestResourcePoolId(IDGenerator.nextStr());
allocation.setRetryOnFail(true);
allocation.setRetryTimes(10);
allocation.setRetryInterval(1000);
allocation.setRetryType(CaseType.SCENARIO_CASE.getKey());
allocation.setStopOnFail(false);
request.setConfig(allocation);
return request;
}
private TestPlanAllocationCreateRequest buildAllocationUpdateParam(String planId) {
TestPlanAllocationCreateRequest updateParam = new TestPlanAllocationCreateRequest();
TestPlanAllocationTypeExample allocationTypeExample = new TestPlanAllocationTypeExample();
allocationTypeExample.createCriteria().andTestPlanIdEqualTo(planId);
List<TestPlanAllocationType> testPlanAllocationTypes = testPlanAllocationTypeMapper.selectByExample(allocationTypeExample);
List<TestPlanAllocationTypeDTO> allocationTypeDTOS = new ArrayList<>();
testPlanAllocationTypes.forEach(allocationType -> {
TestPlanAllocationTypeDTO allocationTypeDTO = new TestPlanAllocationTypeDTO();
BeanUtils.copyBean(allocationTypeDTO, allocationType);
allocationTypeDTOS.add(allocationTypeDTO);
});
TestPlanCollectionExample collectionExample = new TestPlanCollectionExample();
collectionExample.createCriteria().andTestPlanIdEqualTo(planId);
List<TestPlanCollection> collections = testPlanCollectionMapper.selectByExample(collectionExample);
List<TestPlanCollectionInitDTO> collectionInitDTOS = new ArrayList<>();
collections.forEach(collection -> {
TestPlanCollectionInitDTO collectionInitDTO = new TestPlanCollectionInitDTO();
BeanUtils.copyBean(collectionInitDTO, collection);
collectionInitDTOS.add(collectionInitDTO);
});
TestPlanAllocationExample example = new TestPlanAllocationExample();
example.createCriteria().andTestPlanIdEqualTo(planId);
TestPlanAllocation allocation = testPlanAllocationMapper.selectByExample(example).get(0);
updateParam.setTypeNodes(allocationTypeDTOS);
updateParam.setCollectionNodes(collectionInitDTOS);
updateParam.setConfig(allocation);
return updateParam;
}
} }