feat(测试计划): 测试计划用例列表支持提交&&关联缺陷

--task=1016112 --user=宋昌昌 【测试计划】测试计划可一键提交缺陷-后端 https://www.tapd.cn/55049933/s/1570490
This commit is contained in:
song-cc-rock 2024-08-28 15:18:24 +08:00 committed by Craftsman
parent bf1860faa2
commit 4192b7dfe5
9 changed files with 237 additions and 59 deletions

View File

@ -5,6 +5,7 @@ import com.github.pagehelper.PageHelper;
import io.metersphere.api.dto.definition.ApiReportDTO;
import io.metersphere.api.dto.definition.ApiReportDetailDTO;
import io.metersphere.api.service.definition.ApiReportService;
import io.metersphere.dto.BugProviderDTO;
import io.metersphere.plan.dto.request.*;
import io.metersphere.plan.dto.response.TestPlanApiCasePageResponse;
import io.metersphere.plan.dto.response.TestPlanAssociationResponse;
@ -12,6 +13,8 @@ import io.metersphere.plan.dto.response.TestPlanOperationResponse;
import io.metersphere.plan.service.TestPlanApiCaseBatchRunService;
import io.metersphere.plan.service.TestPlanApiCaseLogService;
import io.metersphere.plan.service.TestPlanApiCaseService;
import io.metersphere.plan.service.TestPlanFunctionalCaseService;
import io.metersphere.request.BugPageProviderRequest;
import io.metersphere.sdk.constants.HttpMethodConstants;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
@ -168,4 +171,29 @@ public class TestPlanApiCaseController {
public void batchMove(@Validated @RequestBody TestPlanApiCaseBatchMoveRequest request) {
testPlanApiCaseService.batchMove(request);
}
@PostMapping("/associate/bug/page")
@Operation(summary = "测试计划-计划详情-接口用例-获取待关联缺陷列表")
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
@RequiresPermissions(PermissionConstants.TEST_PLAN_READ)
public Pager<List<BugProviderDTO>> associateBugList(@Validated @RequestBody BugPageProviderRequest request) {
Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize());
return PageUtils.setPageInfo(page, testPlanApiCaseService.bugPage(request));
}
@PostMapping("/associate/bug")
@Operation(summary = "测试计划-计划详情-接口用例-关联缺陷")
@RequiresPermissions(PermissionConstants.TEST_PLAN_READ_EXECUTE)
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
public void associateBug(@Validated @RequestBody TestPlanCaseAssociateBugRequest request) {
testPlanApiCaseService.associateBug(request, SessionUtils.getUserId());
}
@GetMapping("/disassociate/bug/{id}")
@Operation(summary = "测试计划-计划详情-接口用例-取消关联缺陷")
@RequiresPermissions(PermissionConstants.TEST_PLAN_READ_EXECUTE)
@Log(type = OperationLogType.DISASSOCIATE, expression = "#msClass.disassociateBugLog(#id)", msClass = TestPlanFunctionalCaseService.class)
public void disassociateBug(@PathVariable String id) {
testPlanApiCaseService.disassociateBug(id);
}
}

View File

@ -5,6 +5,7 @@ import com.github.pagehelper.PageHelper;
import io.metersphere.api.dto.scenario.ApiScenarioReportDTO;
import io.metersphere.api.dto.scenario.ApiScenarioReportDetailDTO;
import io.metersphere.api.service.scenario.ApiScenarioReportService;
import io.metersphere.dto.BugProviderDTO;
import io.metersphere.plan.dto.request.*;
import io.metersphere.plan.dto.response.TestPlanApiScenarioPageResponse;
import io.metersphere.plan.dto.response.TestPlanAssociationResponse;
@ -12,6 +13,7 @@ import io.metersphere.plan.dto.response.TestPlanOperationResponse;
import io.metersphere.plan.service.TestPlanApiScenarioBatchRunService;
import io.metersphere.plan.service.TestPlanApiScenarioLogService;
import io.metersphere.plan.service.TestPlanApiScenarioService;
import io.metersphere.request.BugPageProviderRequest;
import io.metersphere.sdk.constants.HttpMethodConstants;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
@ -154,4 +156,29 @@ public class TestPlanApiScenarioController {
public void batchMove(@Validated @RequestBody BaseBatchMoveRequest request) {
testPlanApiScenarioService.batchMove(request);
}
@PostMapping("/associate/bug/page")
@Operation(summary = "测试计划-计划详情-场景用例-获取待关联缺陷列表")
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
@RequiresPermissions(PermissionConstants.TEST_PLAN_READ)
public Pager<List<BugProviderDTO>> associateBugList(@Validated @RequestBody BugPageProviderRequest request) {
Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize());
return PageUtils.setPageInfo(page, testPlanApiScenarioService.bugPage(request));
}
@PostMapping("/associate/bug")
@Operation(summary = "测试计划-计划详情-场景用例-关联缺陷")
@RequiresPermissions(PermissionConstants.TEST_PLAN_READ_EXECUTE)
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
public void associateBug(@Validated @RequestBody TestPlanCaseAssociateBugRequest request) {
testPlanApiScenarioService.associateBug(request, SessionUtils.getUserId());
}
@GetMapping("/disassociate/bug/{id}")
@Operation(summary = "测试计划-计划详情-场景用例-取消关联缺陷")
@RequiresPermissions(PermissionConstants.TEST_PLAN_READ_EXECUTE)
@Log(type = OperationLogType.DISASSOCIATE, expression = "#msClass.disassociateBugLog(#id)", msClass = TestPlanApiScenarioService.class)
public void disassociateBug(@PathVariable String id) {
testPlanApiScenarioService.disassociateBug(id);
}
}

View File

@ -115,7 +115,7 @@ public class TestPlanFunctionalCaseController {
}
@PostMapping("/associate/bug/page")
@Operation(summary = "测试计划-计划详情-功能用例-获取缺陷列表")
@Operation(summary = "测试计划-计划详情-功能用例-获取待关联缺陷列表")
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
@RequiresPermissions(PermissionConstants.TEST_PLAN_READ)
public Pager<List<BugProviderDTO>> associateBugList(@Validated @RequestBody BugPageProviderRequest request) {

View File

@ -845,6 +845,15 @@ public class TestPlanApiCaseService extends TestPlanResourceService {
}
}
/**
* 关联缺陷 (单条用例)
* @param request 请求参数
* @param userId 用户ID
*/
public void associateBug(TestPlanCaseAssociateBugRequest request, String userId) {
super.associateBug(request, userId, CaseType.API_CASE.getKey());
}
private void moveCaseToCollection(List<String> ids, String targetCollectionId) {
AtomicLong nextOrder = new AtomicLong(getNextOrder(targetCollectionId));
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);

View File

@ -706,6 +706,15 @@ public class TestPlanApiScenarioService extends TestPlanResourceService {
}
}
/**
* 关联缺陷 (单条用例)
* @param request 请求参数
* @param userId 用户ID
*/
public void associateBug(TestPlanCaseAssociateBugRequest request, String userId) {
super.associateBug(request, userId, CaseType.SCENARIO_CASE.getKey());
}
private void moveCaseToCollection(List<String> ids, String targetCollectionId) {
AtomicLong nextOrder = new AtomicLong(getNextOrder(targetCollectionId));
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);

View File

@ -3,7 +3,6 @@ package io.metersphere.plan.service;
import com.alibaba.excel.util.BooleanUtils;
import io.metersphere.api.domain.ApiScenario;
import io.metersphere.api.domain.ApiTestCase;
import io.metersphere.bug.domain.Bug;
import io.metersphere.bug.domain.BugRelationCase;
import io.metersphere.bug.domain.BugRelationCaseExample;
import io.metersphere.bug.dto.CaseRelateBugDTO;
@ -36,22 +35,16 @@ import io.metersphere.project.dto.ModuleCountDTO;
import io.metersphere.project.dto.MoveNodeSortDTO;
import io.metersphere.provider.BaseAssociateBugProvider;
import io.metersphere.request.AssociateBugPageRequest;
import io.metersphere.request.BugPageProviderRequest;
import io.metersphere.sdk.constants.*;
import io.metersphere.sdk.dto.AssociateCaseDTO;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.SubListUtils;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.dto.LogInsertModule;
import io.metersphere.system.dto.sdk.BaseTreeNode;
import io.metersphere.system.dto.sdk.SessionUser;
import io.metersphere.system.dto.user.UserDTO;
import io.metersphere.system.log.aspect.OperationLogAspect;
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.mapper.ExtUserMapper;
import io.metersphere.system.notice.constants.NoticeConstants;
import io.metersphere.system.service.UserLoginService;
@ -491,56 +484,8 @@ public class TestPlanFunctionalCaseService extends TestPlanResourceService {
}
}
public List<BugProviderDTO> bugPage(BugPageProviderRequest request) {
return baseAssociateBugProvider.getBugList("bug_relation_case", "test_plan_case_id", "bug_id", request);
}
public void associateBug(TestPlanCaseAssociateBugRequest request, String userId) {
List<String> ids = baseAssociateBugProvider.getSelectBugs(request, false);
if (CollectionUtils.isNotEmpty(ids)) {
SubListUtils.dealForSubList(ids, 100, subList -> {
List<BugRelationCase> list = new ArrayList<>();
subList.forEach(id -> {
BugRelationCase bugRelationCase = new BugRelationCase();
bugRelationCase.setId(IDGenerator.nextStr());
bugRelationCase.setBugId(id);
bugRelationCase.setCaseId(request.getCaseId());
bugRelationCase.setCaseType(CaseType.FUNCTIONAL_CASE.getKey());
bugRelationCase.setCreateUser(userId);
bugRelationCase.setCreateTime(System.currentTimeMillis());
bugRelationCase.setUpdateTime(System.currentTimeMillis());
bugRelationCase.setTestPlanCaseId(request.getTestPlanCaseId());
bugRelationCase.setTestPlanId(request.getTestPlanId());
list.add(bugRelationCase);
});
bugRelationCaseMapper.batchInsert(list);
});
}
}
public void disassociateBug(String id) {
baseAssociateBugProvider.disassociateBug(id);
}
public LogDTO disassociateBugLog(String id) {
BugRelationCase bugRelationCase = bugRelationCaseMapper.selectByPrimaryKey(id);
if (bugRelationCase != null) {
Bug bug = bugMapper.selectByPrimaryKey(bugRelationCase.getBugId());
LogDTO dto = new LogDTO(
null,
null,
bugRelationCase.getBugId(),
null,
OperationLogType.DISASSOCIATE.name(),
OperationLogModule.TEST_PLAN,
bug.getTitle() + "缺陷");
dto.setPath(OperationLogAspect.getPath());
dto.setMethod(HttpMethodConstants.GET.name());
dto.setOriginalValue(JSON.toJSONBytes(bugRelationCase));
return dto;
}
return null;
super.associateBug(request, userId, CaseType.FUNCTIONAL_CASE.getKey());
}
/**

View File

@ -1,5 +1,10 @@
package io.metersphere.plan.service;
import io.metersphere.bug.domain.Bug;
import io.metersphere.bug.domain.BugRelationCase;
import io.metersphere.bug.mapper.BugMapper;
import io.metersphere.bug.mapper.BugRelationCaseMapper;
import io.metersphere.dto.BugProviderDTO;
import io.metersphere.plan.domain.TestPlan;
import io.metersphere.plan.domain.TestPlanCollectionExample;
import io.metersphere.plan.dto.ModuleSelectDTO;
@ -8,21 +13,33 @@ import io.metersphere.plan.dto.TestPlanResourceAssociationParam;
import io.metersphere.plan.dto.TestPlanResourceExecResultDTO;
import io.metersphere.plan.dto.request.BaseCollectionAssociateRequest;
import io.metersphere.plan.dto.request.BasePlanCaseBatchRequest;
import io.metersphere.plan.dto.request.TestPlanCaseAssociateBugRequest;
import io.metersphere.plan.dto.response.TestPlanAssociationResponse;
import io.metersphere.plan.mapper.TestPlanCollectionMapper;
import io.metersphere.plan.mapper.TestPlanMapper;
import io.metersphere.provider.BaseAssociateBugProvider;
import io.metersphere.request.BugPageProviderRequest;
import io.metersphere.sdk.constants.HttpMethodConstants;
import io.metersphere.sdk.constants.ModuleConstants;
import io.metersphere.sdk.dto.AssociateCaseDTO;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.SubListUtils;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.dto.LogInsertModule;
import io.metersphere.system.dto.sdk.SessionUser;
import io.metersphere.system.log.aspect.OperationLogAspect;
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.uid.IDGenerator;
import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
@ -38,9 +55,13 @@ public abstract class TestPlanResourceService extends TestPlanSortService {
@Resource
private TestPlanMapper testPlanMapper;
@Resource
private TestPlanResourceLogService testPlanResourceLogService;
@Resource
private TestPlanCollectionMapper testPlanCollectionMapper;
@Resource
private BaseAssociateBugProvider baseAssociateBugProvider;
@Resource
private BugRelationCaseMapper bugRelationCaseMapper;
@Resource
private BugMapper bugMapper;
public static final String MODULE_ALL = "all";
@ -130,4 +151,76 @@ public abstract class TestPlanResourceService extends TestPlanSortService {
AssociateCaseDTO associateCaseDTO = new AssociateCaseDTO(excludeIds, selectIds, moduleIds);
return associateCaseDTO;
}
/**
* 获取待关联的缺陷列表
* @param request 请求参数
* @return 缺陷列表
*/
public List<BugProviderDTO> bugPage(BugPageProviderRequest request) {
return baseAssociateBugProvider.getBugList("bug_relation_case", "test_plan_case_id", "bug_id", request);
}
/**
* 用例关联缺陷(单条用例)
* @param request 请求参数
* @param userId 用户ID
* @param caseType 用例类型
*/
public void associateBug(TestPlanCaseAssociateBugRequest request, String userId, String caseType) {
List<String> ids = baseAssociateBugProvider.getSelectBugs(request, false);
if (org.apache.commons.collections.CollectionUtils.isNotEmpty(ids)) {
SubListUtils.dealForSubList(ids, 100, subList -> {
List<BugRelationCase> list = new ArrayList<>();
subList.forEach(id -> {
BugRelationCase bugRelationCase = new BugRelationCase();
bugRelationCase.setId(IDGenerator.nextStr());
bugRelationCase.setBugId(id);
bugRelationCase.setCaseId(request.getCaseId());
bugRelationCase.setCaseType(caseType);
bugRelationCase.setCreateUser(userId);
bugRelationCase.setCreateTime(System.currentTimeMillis());
bugRelationCase.setUpdateTime(System.currentTimeMillis());
bugRelationCase.setTestPlanCaseId(request.getTestPlanCaseId());
bugRelationCase.setTestPlanId(request.getTestPlanId());
list.add(bugRelationCase);
});
bugRelationCaseMapper.batchInsert(list);
});
}
}
/**
* 取消关联缺陷
* @param id 关系ID
*/
public void disassociateBug(String id) {
baseAssociateBugProvider.disassociateBug(id);
}
/**
* 取消关联缺陷日志
* @param id 关系ID
* @return 日志
*/
public LogDTO disassociateBugLog(String id) {
BugRelationCase bugRelationCase = bugRelationCaseMapper.selectByPrimaryKey(id);
if (bugRelationCase != null) {
Bug bug = bugMapper.selectByPrimaryKey(bugRelationCase.getBugId());
LogDTO dto = new LogDTO(
null,
null,
bugRelationCase.getBugId(),
null,
OperationLogType.DISASSOCIATE.name(),
OperationLogModule.TEST_PLAN,
bug.getTitle() + "缺陷");
dto.setPath(OperationLogAspect.getPath());
dto.setMethod(HttpMethodConstants.GET.name());
dto.setOriginalValue(JSON.toJSONBytes(bugRelationCase));
return dto;
}
return null;
}
}

View File

@ -28,6 +28,7 @@ import io.metersphere.plan.dto.response.TestPlanOperationResponse;
import io.metersphere.plan.mapper.TestPlanApiCaseMapper;
import io.metersphere.plan.service.TestPlanApiCaseService;
import io.metersphere.project.mapper.ExtBaseProjectVersionMapper;
import io.metersphere.request.BugPageProviderRequest;
import io.metersphere.sdk.constants.ApiBatchRunMode;
import io.metersphere.sdk.constants.ApiExecuteResourceType;
import io.metersphere.sdk.constants.PermissionConstants;
@ -76,6 +77,9 @@ public class TestPlanApiCaseControllerTests extends BaseTest {
public static final String BATCH_RUN = "batch/run";
public static final String RUN_WITH_REPORT_ID = "run/{0}?reportId={1}";
private static final String API_CASE_BATCH_MOVE = "/batch/move";
private static final String BUG_ASSOCIATE_PAGE = "/associate/bug/page";
private static final String ASSOCIATE_BUG = "/associate/bug";
private static final String DISASSOCIATE_BUG = "/disassociate/bug/{0}";
@Resource
private TestPlanApiCaseService testPlanApiCaseService;
@ -526,4 +530,34 @@ public class TestPlanApiCaseControllerTests extends BaseTest {
request.setSelectAll(true);
this.requestPostWithOk(API_CASE_BATCH_MOVE, request);
}
@Test
@Order(12)
void testAssociateBugPage() throws Exception {
BugPageProviderRequest request = new BugPageProviderRequest();
request.setSourceId("test_plan_case_id");
request.setProjectId(DEFAULT_PROJECT_ID);
request.setCurrent(1);
request.setPageSize(10);
this.requestPostWithOk(BUG_ASSOCIATE_PAGE, request);
}
@Test
@Order(13)
void testAssociateBug() throws Exception {
TestPlanCaseAssociateBugRequest request = new TestPlanCaseAssociateBugRequest();
request.setTestPlanCaseId("test_plan_case_id");
request.setCaseId("case_id");
request.setTestPlanId("test_plan_id");
request.setProjectId(DEFAULT_PROJECT_ID);
request.setSelectAll(false);
request.setSelectIds(List.of("oasis"));
this.requestPost(ASSOCIATE_BUG, request);
}
@Test
@Order(14)
void testDisassociateBug() throws Exception {
this.requestGet(DISASSOCIATE_BUG, "test_plan_case_id");
}
}

View File

@ -29,6 +29,7 @@ import io.metersphere.plan.service.TestPlanApiScenarioService;
import io.metersphere.project.api.assertion.MsResponseCodeAssertion;
import io.metersphere.project.api.assertion.MsScriptAssertion;
import io.metersphere.project.mapper.ExtBaseProjectVersionMapper;
import io.metersphere.request.BugPageProviderRequest;
import io.metersphere.sdk.constants.ApiBatchRunMode;
import io.metersphere.sdk.constants.MsAssertionCondition;
import io.metersphere.sdk.constants.PermissionConstants;
@ -75,6 +76,9 @@ public class TestPlanApiScenarioControllerTests extends BaseTest {
public static final String API_SCENARIO_BATCH_UPDATE_EXECUTOR_URL = "batch/update/executor";
private static final String URL_POST_RESOURCE_API_SCENARIO_SORT = "/sort";
private static final String API_SCENARIO_BATCH_MOVE_URL = "/batch/move";
private static final String BUG_ASSOCIATE_PAGE = "/associate/bug/page";
private static final String ASSOCIATE_BUG = "/associate/bug";
private static final String DISASSOCIATE_BUG = "/disassociate/bug/{0}";
@Resource
private TestPlanApiScenarioService testPlanApiScenarioService;
@ -569,4 +573,33 @@ public class TestPlanApiScenarioControllerTests extends BaseTest {
requestGetPermissionTest(PermissionConstants.TEST_PLAN_REPORT_READ, "/report/get/detail/plan-test-scenario-report-id/plan-test-scenario-report-step-id1");
}
@Test
@Order(7)
void testAssociateBugPage() throws Exception {
BugPageProviderRequest request = new BugPageProviderRequest();
request.setSourceId("test_plan_case_id");
request.setProjectId(DEFAULT_PROJECT_ID);
request.setCurrent(1);
request.setPageSize(10);
this.requestPostWithOk(BUG_ASSOCIATE_PAGE, request);
}
@Test
@Order(8)
void testAssociateBug() throws Exception {
TestPlanCaseAssociateBugRequest request = new TestPlanCaseAssociateBugRequest();
request.setTestPlanCaseId("test_plan_case_id");
request.setCaseId("case_id");
request.setTestPlanId("test_plan_id");
request.setProjectId(DEFAULT_PROJECT_ID);
request.setSelectAll(false);
request.setSelectIds(List.of("oasis"));
this.requestPost(ASSOCIATE_BUG, request);
}
@Test
@Order(9)
void testDisassociateBug() throws Exception {
this.requestGet(DISASSOCIATE_BUG, "test_plan_case_id");
}
}