feat(测试计划): 测试计划详情用例脑图批量新增缺陷

This commit is contained in:
WangXu10 2024-08-29 15:28:37 +08:00 committed by Craftsman
parent 26f1f82686
commit a63d9e811a
9 changed files with 297 additions and 5 deletions

View File

@ -4,9 +4,11 @@ import io.metersphere.functional.domain.CaseReviewHistory;
import io.metersphere.functional.domain.FunctionalCase;
import io.metersphere.functional.domain.FunctionalCaseComment;
import io.metersphere.plan.domain.TestPlanCaseExecuteHistory;
import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.Translator;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
@ -39,10 +41,11 @@ public interface FunctionalCaseExportConverter {
default String parseHtml(String html) {
Pattern pattern = Pattern.compile("<p[^>]*>(.*?)</p>");
Matcher matcher = pattern.matcher(html);
if (matcher.find()) {
String content = matcher.group(1);
return content;
List<String> contents = new ArrayList<>();
while (matcher.find()) {
contents.add(matcher.group(1));
}
return StringUtils.EMPTY;
String join = String.join(StringUtils.SPACE, contents);
return join;
}
}

View File

@ -0,0 +1,46 @@
package io.metersphere.plan.controller;
import io.metersphere.bug.domain.Bug;
import io.metersphere.bug.dto.request.BugEditRequest;
import io.metersphere.bug.service.BugService;
import io.metersphere.plan.dto.request.TestPlanCaseMinderBatchAddBugRequest;
import io.metersphere.plan.service.TestPlanFunctionalCaseMinderService;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.system.security.CheckOwner;
import io.metersphere.system.utils.SessionUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@Tag(name = "测试计划-功能用例-脑图-操作")
@RestController
@RequestMapping("/test-plan/functional/case/minder")
public class TestPlanFunctionalCaseMinderController {
@Resource
private BugService bugService;
@Resource
private TestPlanFunctionalCaseMinderService testPlanFunctionalCaseMinderService;
@PostMapping("/batch/add-bug")
@Operation(summary = "测试计划-功能用例-脑图-批量添加缺陷")
@RequiresPermissions(PermissionConstants.TEST_PLAN_READ_EXECUTE)
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
public void minderBatchAddBug(@Validated @RequestPart("request") TestPlanCaseMinderBatchAddBugRequest request,
@RequestPart(value = "files", required = false) List<MultipartFile> files) {
BugEditRequest bugEditRequest = new BugEditRequest();
BeanUtils.copyBean(bugEditRequest, request);
Bug bug = bugService.addOrUpdate(bugEditRequest, files, SessionUtils.getUserId(), SessionUtils.getCurrentOrganizationId(), false);
testPlanFunctionalCaseMinderService.minderBatchAssociateBug(request, bug.getId(), SessionUtils.getUserId());
}
}

View File

@ -0,0 +1,22 @@
package io.metersphere.plan.dto.request;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
/**
* @author wx
*/
@Data
public class TestPlanCaseMinderBatchAddBugRequest extends TestPlanCaseBatchAddBugRequest {
@Schema(description = "脑图选中的模块id集合")
private List<String> minderModuleIds;
@Schema(description = "脑图选中的用例id集合")
private List<String> minderCaseIds;
@Schema(description = "脑图选中的项目id集合")
private List<String> minderProjectIds;
}

View File

@ -1,5 +1,6 @@
package io.metersphere.plan.mapper;
import io.metersphere.functional.domain.FunctionalCaseModule;
import io.metersphere.functional.dto.FunctionalCaseModuleCountDTO;
import io.metersphere.functional.dto.FunctionalCaseModuleDTO;
import io.metersphere.functional.dto.ProjectOptionDTO;
@ -8,6 +9,7 @@ import io.metersphere.plan.dto.ResourceSelectParam;
import io.metersphere.plan.dto.TestPlanCaseRunResultCount;
import io.metersphere.plan.dto.TestPlanResourceExecResultDTO;
import io.metersphere.plan.dto.request.BasePlanCaseBatchRequest;
import io.metersphere.plan.dto.request.TestPlanCaseMinderBatchAddBugRequest;
import io.metersphere.plan.dto.request.TestPlanCaseModuleRequest;
import io.metersphere.plan.dto.request.TestPlanCaseRequest;
import io.metersphere.plan.dto.response.TestPlanCasePageResponse;
@ -16,6 +18,7 @@ import io.metersphere.project.dto.ModuleCountDTO;
import io.metersphere.project.dto.NodeSortQueryParam;
import org.apache.ibatis.annotations.Param;
import java.util.Collection;
import java.util.List;
public interface ExtTestPlanFunctionalCaseMapper {
@ -73,4 +76,10 @@ public interface ExtTestPlanFunctionalCaseMapper {
List<String> selectTestPlanIdByFunctionCaseId(String functionalCaseId);
List<TestPlanResourceExecResultDTO> selectDistinctExecResultByTestPlanIds(@Param("testPlanIds") List<String> testPlanIds);
Collection<String> selectIdsByProjectIds(@Param("request") TestPlanCaseMinderBatchAddBugRequest request);
List<FunctionalCaseModule> selectProjectByModuleIds(@Param("moduleIds") List<String> moduleIds);
Collection<String> selectIdsByModuleIds(@Param("request") TestPlanCaseMinderBatchAddBugRequest request, @Param("minderModuleIds") List<String> minderModuleIds);
}

View File

@ -666,4 +666,53 @@
AND test_plan.status != 'ARCHIVED'
</select>
<select id="selectIdsByProjectIds" resultType="java.lang.String">
SELECT
test_plan_functional_case.id
FROM
test_plan_functional_case
LEFT JOIN functional_case ON test_plan_functional_case.functional_case_id = functional_case.id
WHERE
test_plan_functional_case.test_plan_id = #{request.testPlanId}
AND functional_case.deleted = false
<include refid="queryWhereConditionByBatchQueryRequest"/>
and functional_case.project_id in
<foreach collection="request.getMinderProjectIds()" item="projectId" open="(" separator="," close=")">
#{projectId}
</foreach>
</select>
<select id="selectProjectByModuleIds" resultType="io.metersphere.functional.domain.FunctionalCaseModule">
SELECT id, project_id
FROM functional_case_module
WHERE id IN
<foreach collection="moduleIds" item="moduleId" separator="," open="(" close=")">
<choose>
<when test="moduleId.contains('_root')">
'root'
</when>
<otherwise>
#{moduleId}
</otherwise>
</choose>
</foreach>
</select>
<select id="selectIdsByModuleIds" resultType="java.lang.String">
SELECT
test_plan_functional_case.id
FROM
test_plan_functional_case
LEFT JOIN functional_case ON test_plan_functional_case.functional_case_id = functional_case.id
WHERE
test_plan_functional_case.test_plan_id = #{request.testPlanId}
AND functional_case.deleted = false
<include refid="queryWhereConditionByBatchQueryRequest"/>
and functional_case.module_id in
<foreach collection="minderModuleIds" item="moduleId" open="(" separator="," close=")">
#{moduleId}
</foreach>
</select>
</mapper>

View File

@ -0,0 +1,127 @@
package io.metersphere.plan.service;
import io.metersphere.bug.domain.BugRelationCase;
import io.metersphere.bug.mapper.BugRelationCaseMapper;
import io.metersphere.functional.domain.FunctionalCaseModule;
import io.metersphere.functional.service.FunctionalCaseModuleService;
import io.metersphere.plan.dto.request.TestPlanCaseMinderBatchAddBugRequest;
import io.metersphere.plan.mapper.ExtTestPlanFunctionalCaseMapper;
import io.metersphere.sdk.constants.CaseType;
import io.metersphere.sdk.util.SubListUtils;
import io.metersphere.system.dto.sdk.BaseTreeNode;
import io.metersphere.system.uid.IDGenerator;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
@Transactional(rollbackFor = Exception.class)
public class TestPlanFunctionalCaseMinderService {
@Resource
private ExtTestPlanFunctionalCaseMapper extTestPlanFunctionalCaseMapper;
@Resource
private FunctionalCaseModuleService functionalCaseModuleService;
@Resource
private TestPlanFunctionalCaseService testPlanFunctionalCaseService;
@Resource
private BugRelationCaseMapper bugRelationCaseMapper;
public void minderBatchAssociateBug(TestPlanCaseMinderBatchAddBugRequest request, String bugId, String userId) {
//获取脑图选中的用例id集合
List<String> ids = getMinderSelectIds(request);
if (CollectionUtils.isNotEmpty(ids)) {
SubListUtils.dealForSubList(ids, 500, (subList) -> {
Map<String, String> caseMap = testPlanFunctionalCaseService.getCaseMap(subList);
List<BugRelationCase> list = new ArrayList<>();
subList.forEach(id -> {
BugRelationCase bugRelationCase = new BugRelationCase();
bugRelationCase.setId(IDGenerator.nextStr());
bugRelationCase.setBugId(bugId);
bugRelationCase.setCaseId(caseMap.get(id));
bugRelationCase.setCaseType(CaseType.FUNCTIONAL_CASE.getKey());
bugRelationCase.setCreateUser(userId);
bugRelationCase.setCreateTime(System.currentTimeMillis());
bugRelationCase.setUpdateTime(System.currentTimeMillis());
bugRelationCase.setTestPlanCaseId(id);
bugRelationCase.setTestPlanId(request.getTestPlanId());
list.add(bugRelationCase);
});
bugRelationCaseMapper.batchInsert(list);
});
}
}
private List<String> getMinderSelectIds(TestPlanCaseMinderBatchAddBugRequest request) {
if (request.isSelectAll()) {
//全选
List<String> ids = extTestPlanFunctionalCaseMapper.getIds(request, false);
if (CollectionUtils.isNotEmpty(request.getExcludeIds())) {
ids.removeAll(request.getExcludeIds());
}
return ids;
} else {
List<String> ids = new ArrayList<>();
//项目
if (CollectionUtils.isNotEmpty(request.getMinderProjectIds())) {
ids.addAll(extTestPlanFunctionalCaseMapper.selectIdsByProjectIds(request));
}
//模块
if (CollectionUtils.isNotEmpty(request.getMinderModuleIds())) {
//获取模块及子模块
List<FunctionalCaseModule> modules = extTestPlanFunctionalCaseMapper.selectProjectByModuleIds(request.getMinderModuleIds());
Map<String, List<FunctionalCaseModule>> moduleMaps = modules.stream().collect(Collectors.groupingBy(FunctionalCaseModule::getProjectId));
List<String> minderModuleIds = new LinkedList<>();
moduleMaps.forEach((k, v) -> {
buildIdsByModule(k, v, minderModuleIds);
});
ids.addAll(extTestPlanFunctionalCaseMapper.selectIdsByModuleIds(request, minderModuleIds));
}
//用例
if (CollectionUtils.isNotEmpty(request.getMinderCaseIds())) {
ids.addAll(request.getMinderCaseIds());
}
return ids;
}
}
private void buildIdsByModule(String projectId, List<FunctionalCaseModule> modules, List<String> moduleIds) {
List<BaseTreeNode> tree = functionalCaseModuleService.getTree(projectId);
modules.forEach(module -> {
moduleIds.addAll(getModuleId(tree, module.getId()));
});
}
private List<String> getModuleId(List<BaseTreeNode> tree, String moduleId) {
List<String> nodeIds = new ArrayList<>();
for (BaseTreeNode node : tree) {
if (node.getId().equals(moduleId)) {
nodeIds.add(node.getId());
getChildrenModuleId(node.getChildren(), nodeIds);
} else {
getModuleId(node.getChildren(), moduleId);
}
}
return nodeIds;
}
private void getChildrenModuleId(List<BaseTreeNode> children, List<String> nodeIds) {
if (CollectionUtils.isNotEmpty(children)) {
for (BaseTreeNode child : children) {
nodeIds.add(child.getId());
getChildrenModuleId(child.getChildren(), nodeIds);
}
}
}
}

View File

@ -969,7 +969,7 @@ public class TestPlanFunctionalCaseService extends TestPlanResourceService {
}
}
private Map<String, String> getCaseMap(List<String> ids) {
public Map<String, String> getCaseMap(List<String> ids) {
TestPlanFunctionalCaseExample example = new TestPlanFunctionalCaseExample();
example.createCriteria().andIdIn(ids);
List<TestPlanFunctionalCase> caseList = testPlanFunctionalCaseMapper.selectByExample(example);

View File

@ -22,6 +22,7 @@ import io.metersphere.plan.service.TestPlanFunctionalCaseService;
import io.metersphere.provider.BaseAssociateBugProvider;
import io.metersphere.request.AssociateBugPageRequest;
import io.metersphere.request.BugPageProviderRequest;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.handler.ResultHolder;
@ -68,6 +69,8 @@ public class TestPlanCaseControllerTests extends BaseTest {
public static final String FUNCTIONAL_CASE_BATCH_MOVE_URL = "/test-plan/functional/case/batch/move";
public static final String FUNCTIONAL_CASE_BATCH_ADD_BUG_URL = "/test-plan/functional/case/batch/add-bug";
public static final String FUNCTIONAL_CASE_BATCH_ASSOCIATE_BUG_URL = "/test-plan/functional/case/batch/associate-bug";
public static final String FUNCTIONAL_CASE_MINDER_BATCH_ADD_BUG = "/test-plan/functional/case/minder/batch/add-bug";
@Resource
private TestPlanFunctionalCaseMapper testPlanFunctionalCaseMapper;
@Resource
@ -504,4 +507,32 @@ public class TestPlanCaseControllerTests extends BaseTest {
this.requestPostWithOk(FUNCTIONAL_CASE_BATCH_ASSOCIATE_BUG_URL, request);
}
@Test
@Order(20)
public void testMinderBatchAddBug() throws Exception {
TestPlanCaseMinderBatchAddBugRequest request = new TestPlanCaseMinderBatchAddBugRequest();
TestPlanCaseBatchAddBugRequest bugRequest = buildRequest(false);
BeanUtils.copyBean(request, bugRequest);
request.setSelectAll(true);
List<MockMultipartFile> files = new ArrayList<>();
LinkedMultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
paramMap.add("request", JSON.toJSONString(request));
paramMap.add("files", files);
this.requestMultipartWithOkAndReturn(FUNCTIONAL_CASE_MINDER_BATCH_ADD_BUG, paramMap);
request.setSelectAll(false);
paramMap = new LinkedMultiValueMap<>();
paramMap.add("request", JSON.toJSONString(request));
paramMap.add("files", files);
this.requestMultipartWithOkAndReturn(FUNCTIONAL_CASE_MINDER_BATCH_ADD_BUG, paramMap);
request.setMinderProjectIds(List.of("123"));
request.setMinderModuleIds(List.of("t_1"));
request.setMinderCaseIds(List.of("fc_1"));
paramMap = new LinkedMultiValueMap<>();
paramMap.add("request", JSON.toJSONString(request));
paramMap.add("files", files);
this.requestMultipartWithOkAndReturn(FUNCTIONAL_CASE_MINDER_BATCH_ADD_BUG, paramMap);
}
}

View File

@ -96,3 +96,8 @@ INSERT INTO service_integration(`id`, `plugin_id`, `enable`, `configuration`, `o
INSERT INTO bug_relation_case (id, case_id, bug_id, case_type, test_plan_id, test_plan_case_id, create_user, create_time, update_time) VALUES
('bug_relate_1', 'fc_1', 'bug_1', 'FUNCTIONAL', 'plan_1', 'relate_case_1', 'admin', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
('bug_relate_2', 'fc_1', 'bug_2', 'FUNCTIONAL', 'plan_1', 'relate_case_1', 'admin', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
INSERT INTO functional_case_module(id, project_id, name, parent_id, pos, create_time, create_user, update_time, update_user)
VALUES
('t_1', '123', '测试模块', 'NONE', '1', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin'),
('t_1_1', '123', '测试模块_1', 't_1', '2', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin');