From aa9101c79550e5508f6cea6ff2f793ef845a03e1 Mon Sep 17 00:00:00 2001 From: Jianguo-Genius Date: Thu, 16 May 2024 19:39:17 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E6=B5=8B=E8=AF=95=E8=AE=A1=E5=88=92):=20?= =?UTF-8?q?=E7=BC=96=E5=86=99=E6=B5=8B=E8=AF=95=E8=AE=A1=E5=88=92=E8=B5=84?= =?UTF-8?q?=E6=BA=90=E6=B8=85=E7=90=86=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../io/metersphere/sdk/util/SubListUtils.java | 27 ++-- .../plan/controller/TestPlanController.java | 2 +- .../TestPlanFunctionalCaseController.java | 3 - .../controller/TestPlanReportController.java | 4 +- .../plan/dto/request/ResourceSortRequest.java | 13 +- .../ExtTestPlanFunctionalCaseMapper.java | 2 + .../ExtTestPlanFunctionalCaseMapper.xml | 8 + .../plan/mapper/ExtTestPlanMapper.java | 2 + .../plan/mapper/ExtTestPlanMapper.xml | 5 + .../plan/mapper/ExtTestPlanReportMapper.java | 6 + .../plan/mapper/ExtTestPlanReportMapper.xml | 24 +++ .../service/CleanupPlanResourceService.java | 7 +- .../CleanupTestPlanReportServiceImpl.java | 35 ++++ .../plan/service/TestPlanApiCaseService.java | 5 + .../service/TestPlanApiScenarioService.java | 5 + .../plan/service/TestPlanBugService.java | 4 + .../TestPlanFunctionalCaseService.java | 23 ++- .../plan/service/TestPlanReportService.java | 63 +++++++- .../plan/service/TestPlanResourceService.java | 13 +- .../plan/service/TestPlanService.java | 38 ++++- .../TestPlanReportControllerTests.java | 54 ++++++- .../plan/controller/TestPlanTests.java | 150 ++++++++++++------ .../plan/service/TestPlanTestService.java | 50 ++++++ 23 files changed, 443 insertions(+), 100 deletions(-) create mode 100644 backend/services/test-plan/src/main/java/io/metersphere/plan/service/CleanupTestPlanReportServiceImpl.java diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/util/SubListUtils.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/util/SubListUtils.java index 93476d9ba8..4073430a63 100644 --- a/backend/framework/sdk/src/main/java/io/metersphere/sdk/util/SubListUtils.java +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/util/SubListUtils.java @@ -1,25 +1,30 @@ package io.metersphere.sdk.util; +import org.apache.commons.collections4.CollectionUtils; + +import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; public class SubListUtils { + public static int DEFAULT_BATCH_SIZE = 200; + /** * 将较长的数组截断成较短的数组进行批处理 */ - public static void dealForSubList(List totalList, Integer batchSize, Consumer> subFunc) { - int count = totalList.size(); - int iteratorCount = count / batchSize; - for (int i = 0; i <= iteratorCount; i++) { - int endIndex, startIndex; - startIndex = i * batchSize; - endIndex = ((endIndex = (i + 1) * batchSize) > count) ? count : endIndex; - if (endIndex == startIndex) { - break; - } - List subList = totalList.subList(startIndex, endIndex); + public static void dealForSubList(List totalList, int batchSize, Consumer> subFunc) { + if (CollectionUtils.isEmpty(totalList)) { + return; + } + List dealList = new ArrayList<>(totalList); + while (dealList.size() > batchSize) { + List subList = dealList.subList(0, batchSize); subFunc.accept(subList); + dealList = dealList.subList(subList.size(), dealList.size()); + } + if (CollectionUtils.isNotEmpty(dealList)) { + subFunc.accept(dealList); } } diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/controller/TestPlanController.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/controller/TestPlanController.java index dba5c0d16c..46840e3603 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/controller/TestPlanController.java +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/controller/TestPlanController.java @@ -74,7 +74,7 @@ public class TestPlanController { @RequiresPermissions(PermissionConstants.TEST_PLAN_READ_ADD) @CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project") @SendNotice(taskType = NoticeConstants.TaskType.TEST_PLAN_TASK, event = NoticeConstants.Event.CREATE, target = "#targetClass.sendAddNotice(#request)", targetClass = TestPlanSendNoticeService.class) - public String add(@Validated @RequestBody TestPlanCreateRequest request) { + public TestPlan add(@Validated @RequestBody TestPlanCreateRequest request) { testPlanManagementService.checkModuleIsOpen(request.getProjectId(), TestPlanResourceConfig.CHECK_TYPE_PROJECT, Collections.singletonList(TestPlanResourceConfig.CONFIG_TEST_PLAN)); return testPlanService.add(request, SessionUtils.getUserId(), "/test-plan/add", HttpMethodConstants.POST.name()); } diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/controller/TestPlanFunctionalCaseController.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/controller/TestPlanFunctionalCaseController.java index da0d264c30..cdf3131eab 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/controller/TestPlanFunctionalCaseController.java +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/controller/TestPlanFunctionalCaseController.java @@ -49,7 +49,6 @@ public class TestPlanFunctionalCaseController { @Resource private TestPlanFunctionalCaseService testPlanFunctionalCaseService; - @PostMapping(value = "/sort") @Operation(summary = "测试计划功能用例-功能用例拖拽排序") @RequiresPermissions(PermissionConstants.TEST_PLAN_READ_UPDATE) @@ -59,7 +58,6 @@ public class TestPlanFunctionalCaseController { return testPlanFunctionalCaseService.sortNode(request, new LogInsertModule(SessionUtils.getUserId(), "/test-plan/functional/case/sort", HttpMethodConstants.POST.name())); } - @PostMapping("/page") @Operation(summary = "测试计划-已关联功能用例分页查询") @RequiresPermissions(PermissionConstants.TEST_PLAN_READ) @@ -69,7 +67,6 @@ public class TestPlanFunctionalCaseController { return PageUtils.setPageInfo(page, testPlanFunctionalCaseService.getFunctionalCasePage(request, false)); } - @GetMapping("/tree/{testPlanId}") @Operation(summary = "测试计划-已关联功能用例列表模块树") @RequiresPermissions(PermissionConstants.TEST_PLAN_READ) diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/controller/TestPlanReportController.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/controller/TestPlanReportController.java index d5dff5757f..d666df3176 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/controller/TestPlanReportController.java +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/controller/TestPlanReportController.java @@ -73,7 +73,7 @@ public class TestPlanReportController { @Log(type = OperationLogType.DELETE, expression = "#msClass.deleteLog(#id)", msClass = TestPlanReportLogService.class) @SendNotice(taskType = NoticeConstants.TaskType.TEST_PLAN_REPORT_TASK, event = NoticeConstants.Event.DELETE, target = "#targetClass.getDto(#id)", targetClass = TestPlanReportNoticeService.class) public void delete(@PathVariable String id) { - testPlanReportService.delete(id); + testPlanReportService.setReportDelete(id); } @PostMapping("/batch-delete") @@ -81,7 +81,7 @@ public class TestPlanReportController { @RequiresPermissions(PermissionConstants.TEST_PLAN_REPORT_READ_DELETE) @CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project") public void batchDelete(@Validated @RequestBody TestPlanReportBatchRequest request) { - testPlanReportService.batchDelete(request, SessionUtils.getUserId()); + testPlanReportService.batchSetReportDelete(request, SessionUtils.getUserId()); } @PostMapping("/gen") diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/dto/request/ResourceSortRequest.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/dto/request/ResourceSortRequest.java index c26a2338bc..14a76bf75c 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/dto/request/ResourceSortRequest.java +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/dto/request/ResourceSortRequest.java @@ -1,23 +1,14 @@ package io.metersphere.plan.dto.request; +import io.metersphere.system.dto.sdk.request.PosRequest; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import lombok.Data; @Data -public class ResourceSortRequest { +public class ResourceSortRequest extends PosRequest { @Schema(description = "测试计划ID") @NotBlank(message = "{test_plan.id.not_blank}") private String testPlanId; - - @Schema(description = "拖拽的节点ID") - private String dragNodeId; - - @Schema(description = "目标节点") - private String dropNodeId; - - @Schema(description = "放入的位置(取值:-1,,0,,1。 -1:dropNodeId节点之前。 0:dropNodeId节点内。 1:dropNodeId节点后)", requiredMode = Schema.RequiredMode.REQUIRED) - private int dropPosition; - } diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanFunctionalCaseMapper.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanFunctionalCaseMapper.java index 40f92cd9c6..4cffb0a0d6 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanFunctionalCaseMapper.java +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanFunctionalCaseMapper.java @@ -20,6 +20,8 @@ public interface ExtTestPlanFunctionalCaseMapper { List selectIdByTestPlanIdOrderByPos(String testPlanId); + List selectIdByTestPlanIds(@Param("testPlanIds") List testPlanIdList); + Long getMaxPosByTestPlanId(String testPlanId); List getIdByParam(ResourceSelectParam resourceSelectParam); diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanFunctionalCaseMapper.xml b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanFunctionalCaseMapper.xml index d42ec2366d..15180e8f0d 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanFunctionalCaseMapper.xml +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanFunctionalCaseMapper.xml @@ -13,6 +13,14 @@ WHERE test_plan_id = #{testPlanId} ORDER BY pos ASC + + diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportMapper.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportMapper.java index 24893ff1bb..33446fe1ae 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportMapper.java +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportMapper.java @@ -62,4 +62,10 @@ public interface ExtTestPlanReportMapper { * @return 关联的用例集合 */ List listReportFunctionalCases(@Param("request")TestPlanReportDetailPageRequest request); + + long countReportByTime(@Param("time") long timeMills, @Param("projectId") String projectId); + + List selectReportIdByProjectIdAndTime(@Param("time") long timeMills, @Param("projectId") String projectId); + + List selectReportIdTestPlanIds(@Param("testPlanIds") List testPlanIds); } diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportMapper.xml b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportMapper.xml index f14aa67035..4a61edc74c 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportMapper.xml +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/mapper/ExtTestPlanReportMapper.xml @@ -51,6 +51,30 @@ #{id} + + + diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/service/CleanupPlanResourceService.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/service/CleanupPlanResourceService.java index 13f429b3e9..28fee0fac5 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/service/CleanupPlanResourceService.java +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/service/CleanupPlanResourceService.java @@ -2,14 +2,19 @@ package io.metersphere.plan.service; import io.metersphere.sdk.util.LogUtils; import io.metersphere.system.service.CleanupProjectResourceService; +import jakarta.annotation.Resource; import org.springframework.stereotype.Component; @Component public class CleanupPlanResourceService implements CleanupProjectResourceService { + @Resource + private TestPlanService testPlanService; @Override public void deleteResources(String projectId) { - LogUtils.info("删除当前项目[" + projectId + "]相关测试计划资源"); + LogUtils.info("删除当前项目[" + projectId + "]的测试计划资源开始"); + testPlanService.deleteByProjectId(projectId); + LogUtils.info("删除当前项目[" + projectId + "]的测试计划资源结束"); } } diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/service/CleanupTestPlanReportServiceImpl.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/service/CleanupTestPlanReportServiceImpl.java new file mode 100644 index 0000000000..2ed47888b5 --- /dev/null +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/service/CleanupTestPlanReportServiceImpl.java @@ -0,0 +1,35 @@ +package io.metersphere.plan.service; + +import io.metersphere.plan.mapper.ExtTestPlanReportMapper; +import io.metersphere.sdk.constants.ProjectApplicationType; +import io.metersphere.sdk.util.LogUtils; +import io.metersphere.system.service.BaseCleanUpReport; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Map; + +import static io.metersphere.sdk.util.ShareUtil.getCleanDate; + +@Component +@Transactional(rollbackFor = Exception.class) +public class CleanupTestPlanReportServiceImpl implements BaseCleanUpReport { + + @Resource + private TestPlanReportService testPlanReportService; + @Resource + private ExtTestPlanReportMapper extTestPlanReportMapper; + + @Override + public void cleanReport(Map map, String projectId) { + LogUtils.info("清理当前项目[" + projectId + "]相关测试计划报告开始:"); + String expr = map.get(ProjectApplicationType.TEST_PLAN.TEST_PLAN_CLEAN_REPORT.name()); + long timeMills = getCleanDate(expr); + List ids = extTestPlanReportMapper.selectReportIdByProjectIdAndTime(timeMills, projectId); + LogUtils.info("清理当前项目[" + projectId + "]相关测试计划报告,共[" + ids.size() + "]条"); + testPlanReportService.cleanAndDeleteReport(ids); + LogUtils.info("清理当前项目[" + projectId + "]相关测试计划报告结束!"); + } +} diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanApiCaseService.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanApiCaseService.java index efbb390550..c8ccc52271 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanApiCaseService.java +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanApiCaseService.java @@ -27,6 +27,11 @@ public class TestPlanApiCaseService extends TestPlanResourceService { return testPlanApiCaseMapper.deleteByExample(example); } + @Override + public long getNextOrder(String projectId) { + return 0; + } + @Override public void updatePos(String id, long pos) { // TODO diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanApiScenarioService.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanApiScenarioService.java index 89c9714c86..78f3a37e42 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanApiScenarioService.java +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanApiScenarioService.java @@ -27,6 +27,11 @@ public class TestPlanApiScenarioService extends TestPlanResourceService { return testPlanApiScenarioMapper.deleteByExample(example); } + @Override + public long getNextOrder(String projectId) { + return 0; + } + @Override public void updatePos(String id, long pos) { // TODO diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanBugService.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanBugService.java index 96b54a94c2..0d4f674df6 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanBugService.java +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanBugService.java @@ -70,6 +70,10 @@ public class TestPlanBugService extends TestPlanResourceService { } + @Override + public long getNextOrder(String projectId) { + return 0; + } @Override public void updatePos(String id, long pos) { diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanFunctionalCaseService.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanFunctionalCaseService.java index ff56b3b61d..06709f537c 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanFunctionalCaseService.java +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanFunctionalCaseService.java @@ -128,12 +128,24 @@ public class TestPlanFunctionalCaseService extends TestPlanResourceService { @Override public int deleteBatchByTestPlanId(List testPlanIdList) { - TestPlanFunctionalCaseExample example = new TestPlanFunctionalCaseExample(); + TestPlanFunctionalCaseExample testPlanFunctionalCaseExample = new TestPlanFunctionalCaseExample(); + testPlanFunctionalCaseExample.createCriteria().andTestPlanIdIn(testPlanIdList); + testPlanFunctionalCaseMapper.deleteByExample(testPlanFunctionalCaseExample); + // 取消关联用例需同步删除计划-用例缺陷关系表 + BugRelationCaseExample example = new BugRelationCaseExample(); example.createCriteria().andTestPlanIdIn(testPlanIdList); - return testPlanFunctionalCaseMapper.deleteByExample(example); + bugRelationCaseMapper.deleteByExample(example); + // todo:song.tianyang 删除执行历史 + + return testPlanFunctionalCaseMapper.deleteByExample(testPlanFunctionalCaseExample); } + @Override + public long getNextOrder(String projectId) { + return 0; + } + @Override public void updatePos(String id, long pos) { extTestPlanFunctionalCaseMapper.updatePos(id, pos); @@ -164,20 +176,21 @@ public class TestPlanFunctionalCaseService extends TestPlanResourceService { } public TestPlanResourceSortResponse sortNode(ResourceSortRequest request, LogInsertModule logInsertModule) { - TestPlanFunctionalCase dragNode = testPlanFunctionalCaseMapper.selectByPrimaryKey(request.getDragNodeId()); + TestPlanFunctionalCase dragNode = testPlanFunctionalCaseMapper.selectByPrimaryKey(request.getMoveId()); TestPlan testPlan = testPlanMapper.selectByPrimaryKey(request.getTestPlanId()); if (dragNode == null) { throw new MSException(Translator.get("test_plan.drag.node.error")); } TestPlanResourceSortResponse response = new TestPlanResourceSortResponse(); AssociationNodeSortDTO sortDTO = super.getNodeSortDTO( - request, + super.getNodeMoveRequest(request), + request.getTestPlanId(), extTestPlanFunctionalCaseMapper::selectDragInfoById, extTestPlanFunctionalCaseMapper::selectNodeByPosOperator ); super.sort(sortDTO); response.setSortNodeNum(1); - testPlanResourceLogService.saveSortLog(testPlan, request.getDragNodeId(), new ResourceLogInsertModule(TestPlanResourceConstants.RESOURCE_FUNCTIONAL_CASE, logInsertModule)); + testPlanResourceLogService.saveSortLog(testPlan, request.getMoveId(), new ResourceLogInsertModule(TestPlanResourceConstants.RESOURCE_FUNCTIONAL_CASE, logInsertModule)); return response; } diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanReportService.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanReportService.java index 9d0907cb34..c8d32e0962 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanReportService.java +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanReportService.java @@ -70,6 +70,10 @@ public class TestPlanReportService { private TestPlanReportSummaryMapper testPlanReportSummaryMapper; @Resource private TestPlanFunctionalCaseMapper testPlanFunctionalCaseMapper; + @Resource + private TestPlanReportFunctionCaseMapper testPlanReportFunctionCaseMapper; + @Resource + private TestPlanReportBugMapper testPlanReportBugMapper; /** * 分页查询报告列表 @@ -98,9 +102,9 @@ public class TestPlanReportService { } /** - * 删除单个报告 + * 业务删除报告 */ - public void delete(String id) { + public void setReportDelete(String id) { TestPlanReport report = checkReport(id); report.setDeleted(true); testPlanReportMapper.updateByPrimaryKeySelective(report); @@ -111,23 +115,72 @@ public class TestPlanReportService { * * @param request 请求参数 */ - public void batchDelete(TestPlanReportBatchRequest request, String userId) { + public void batchSetReportDelete(TestPlanReportBatchRequest request, String userId) { List batchIds = getBatchIds(request); User user = userMapper.selectByPrimaryKey(userId); if (CollectionUtils.isNotEmpty(batchIds)) { - SubListUtils.dealForSubList(batchIds, 500, subList -> { + SubListUtils.dealForSubList(batchIds, SubListUtils.DEFAULT_BATCH_SIZE, subList -> { TestPlanReportExample example = new TestPlanReportExample(); example.createCriteria().andIdIn(subList); TestPlanReport testPlanReport = new TestPlanReport(); testPlanReport.setDeleted(true); testPlanReportMapper.updateByExampleSelective(testPlanReport, example); - testPlanReportLogService.batchDeleteLog(subList, userId, request.getProjectId()); testPlanReportNoticeService.batchSendNotice(subList, user, request.getProjectId(), NoticeConstants.Event.DELETE); }); } } + /** + * 清空测试计划报告(包括summary + * + * @param reportIdList + */ + public void cleanAndDeleteReport(List reportIdList) { + if (CollectionUtils.isNotEmpty(reportIdList)) { + SubListUtils.dealForSubList(reportIdList, SubListUtils.DEFAULT_BATCH_SIZE, subList -> { + TestPlanReportExample example = new TestPlanReportExample(); + example.createCriteria().andIdIn(subList); + TestPlanReport testPlanReport = new TestPlanReport(); + testPlanReport.setDeleted(true); + testPlanReportMapper.updateByExampleSelective(testPlanReport, example); + + this.deleteTestPlanReportBlobs(subList); + }); + } + } + + /** + * 删除测试计划报告(包括summary + */ + public void deleteByTestPlanIds(List testPlanIds) { + if (CollectionUtils.isNotEmpty(testPlanIds)) { + List reportIdList = extTestPlanReportMapper.selectReportIdTestPlanIds(testPlanIds); + + SubListUtils.dealForSubList(reportIdList, SubListUtils.DEFAULT_BATCH_SIZE, subList -> { + TestPlanReportExample example = new TestPlanReportExample(); + example.createCriteria().andIdIn(subList); + testPlanReportMapper.deleteByExample(example); + + this.deleteTestPlanReportBlobs(subList); + }); + } + } + + private void deleteTestPlanReportBlobs(List reportIdList) { + // todo 后续版本增加 api_case\ api_scenario 的清理 + TestPlanReportSummaryExample summaryExample = new TestPlanReportSummaryExample(); + summaryExample.createCriteria().andTestPlanReportIdIn(reportIdList); + testPlanReportSummaryMapper.deleteByExample(summaryExample); + + TestPlanReportFunctionCaseExample testPlanReportFunctionCaseExample = new TestPlanReportFunctionCaseExample(); + testPlanReportFunctionCaseExample.createCriteria().andTestPlanReportIdIn(reportIdList); + testPlanReportFunctionCaseMapper.deleteByExample(testPlanReportFunctionCaseExample); + + TestPlanReportBugExample testPlanReportBugExample = new TestPlanReportBugExample(); + testPlanReportBugExample.createCriteria().andTestPlanReportIdIn(reportIdList); + testPlanReportBugMapper.deleteByExample(testPlanReportBugExample); + } /** * 手动生成报告 * @param request 请求参数 diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanResourceService.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanResourceService.java index 8190a37a11..e961056d69 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanResourceService.java +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanResourceService.java @@ -6,15 +6,16 @@ import io.metersphere.plan.dto.AssociationNodeSortDTO; import io.metersphere.plan.dto.ResourceLogInsertModule; import io.metersphere.plan.dto.TestPlanResourceAssociationParam; import io.metersphere.plan.dto.request.BasePlanCaseBatchRequest; -import io.metersphere.plan.dto.request.ResourceSortRequest; import io.metersphere.plan.dto.response.TestPlanAssociationResponse; import io.metersphere.plan.mapper.TestPlanMapper; import io.metersphere.project.dto.ModuleSortCountResultDTO; import io.metersphere.project.dto.NodeSortQueryParam; +import io.metersphere.project.service.MoveNodeService; import io.metersphere.project.utils.NodeSortUtils; import io.metersphere.sdk.exception.MSException; import io.metersphere.sdk.util.Translator; import io.metersphere.system.dto.LogInsertModule; +import io.metersphere.system.dto.sdk.request.NodeMoveRequest; import jakarta.annotation.Resource; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -29,7 +30,7 @@ import java.util.function.Function; //测试计划关联表 通用方法 @Service @Transactional(rollbackFor = Exception.class) -public abstract class TestPlanResourceService { +public abstract class TestPlanResourceService extends MoveNodeService { @Resource private TestPlanMapper testPlanMapper; @@ -80,7 +81,7 @@ public abstract class TestPlanResourceService { * @param selectPosNodeFunc 通过parentId和pos运算符查询节点的函数 * @return */ - public AssociationNodeSortDTO getNodeSortDTO(ResourceSortRequest request, Function selectIdNodeFunc, Function selectPosNodeFunc) { + public AssociationNodeSortDTO getNodeSortDTO(NodeMoveRequest request, String testPlanId, Function selectIdNodeFunc, Function selectPosNodeFunc) { if (StringUtils.equals(request.getDragNodeId(), request.getDropNodeId())) { //两种节点不能一样 throw new MSException(Translator.get("invalid_parameter") + ": drag node and drop node"); @@ -104,7 +105,7 @@ public abstract class TestPlanResourceService { previousNode = dropNode; NodeSortQueryParam sortParam = new NodeSortQueryParam(); - sortParam.setParentId(request.getTestPlanId()); + sortParam.setParentId(testPlanId); sortParam.setPos(previousNode.getPos()); sortParam.setOperator(MOVE_POS_OPERATOR_MORE); nextNode = selectPosNodeFunc.apply(sortParam); @@ -113,14 +114,14 @@ public abstract class TestPlanResourceService { nextNode = dropNode; NodeSortQueryParam sortParam = new NodeSortQueryParam(); sortParam.setPos(nextNode.getPos()); - sortParam.setParentId(request.getTestPlanId()); + sortParam.setParentId(testPlanId); sortParam.setOperator(MOVE_POS_OPERATOR_LESS); previousNode = selectPosNodeFunc.apply(sortParam); } else { throw new MSException(Translator.get("invalid_parameter") + ": dropPosition"); } - return new AssociationNodeSortDTO(request.getTestPlanId(), dragNode, previousNode, nextNode); + return new AssociationNodeSortDTO(testPlanId, dragNode, previousNode, nextNode); } //排序 diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanService.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanService.java index c85947fc6a..b38cc3d98d 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanService.java +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanService.java @@ -11,8 +11,10 @@ import io.metersphere.sdk.constants.TestPlanConstants; import io.metersphere.sdk.exception.MSException; import io.metersphere.sdk.util.BeanUtils; import io.metersphere.sdk.util.CommonBeanFactory; +import io.metersphere.sdk.util.SubListUtils; import io.metersphere.sdk.util.Translator; import io.metersphere.system.domain.ScheduleExample; +import io.metersphere.system.domain.TestPlanModuleExample; import io.metersphere.system.domain.User; import io.metersphere.system.log.constants.OperationLogType; import io.metersphere.system.mapper.ScheduleMapper; @@ -83,10 +85,10 @@ public class TestPlanService extends TestPlanBaseUtilsService { * @param requestMethod * @return */ - public String 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); testPlanLogService.saveAddLog(testPlan, operator, requestUrl, requestMethod); - return testPlan.getId(); + return testPlan; } @@ -150,7 +152,8 @@ public class TestPlanService extends TestPlanBaseUtilsService { } else { testPlanMapper.deleteByPrimaryKey(id); //级联删除 - this.cascadeDeleteTestPlanIds(Collections.singletonList(id)); + TestPlanReportService testPlanReportService = CommonBeanFactory.getBean(TestPlanReportService.class); + this.cascadeDeleteTestPlanIds(Collections.singletonList(id), testPlanReportService); } //记录日志 testPlanLogService.saveDeleteLog(testPlan, operator, requestUrl, requestMethod); @@ -158,12 +161,14 @@ public class TestPlanService extends TestPlanBaseUtilsService { private void deleteByList(List testPlanIds) { if (CollectionUtils.isNotEmpty(testPlanIds)) { + TestPlanReportService testPlanReportService = CommonBeanFactory.getBean(TestPlanReportService.class); + BatchProcessUtils.consumerByString(testPlanIds, (deleteIds) -> { TestPlanExample testPlanExample = new TestPlanExample(); testPlanExample.createCriteria().andIdIn(deleteIds); testPlanMapper.deleteByExample(testPlanExample); //级联删除 - this.cascadeDeleteTestPlanIds(deleteIds); + this.cascadeDeleteTestPlanIds(deleteIds, testPlanReportService); }); } } @@ -175,6 +180,7 @@ public class TestPlanService extends TestPlanBaseUtilsService { */ private void deleteGroupByList(List testPlanGroupIds) { if (CollectionUtils.isNotEmpty(testPlanGroupIds)) { + TestPlanReportService testPlanReportService = CommonBeanFactory.getBean(TestPlanReportService.class); BatchProcessUtils.consumerByString(testPlanGroupIds, (deleteGroupIds) -> { /* * 计划组删除逻辑{第一版需求: 删除组, 组下的子计划Group置为None}: @@ -187,7 +193,7 @@ public class TestPlanService extends TestPlanBaseUtilsService { List deleteGroupPlanIds = deleteGroupPlans.stream().map(TestPlan::getId).toList(); if (CollectionUtils.isNotEmpty(deleteGroupPlanIds)) { // 级联删除子计划关联的资源(计划组不存在关联的资源) - this.cascadeDeleteTestPlanIds(deleteGroupPlanIds); + this.cascadeDeleteTestPlanIds(deleteGroupPlanIds, testPlanReportService); } testPlanExample.clear(); testPlanExample.createCriteria().andIdIn(ListUtils.union(deleteGroupIds, deleteGroupPlanIds)); @@ -234,8 +240,9 @@ public class TestPlanService extends TestPlanBaseUtilsService { * 级联删除计划关联的资源 * * @param testPlanIds 计划ID集合 + * @param testPlanReportService 这个方法会在批处理中使用,所以service在调用处通过传参的方式传入 */ - private void cascadeDeleteTestPlanIds(List testPlanIds) { + private void cascadeDeleteTestPlanIds(List testPlanIds, TestPlanReportService testPlanReportService) { //删除当前计划对应的资源 Map subTypes = CommonBeanFactory.getBeansOfType(TestPlanResourceService.class); subTypes.forEach((k, t) -> { @@ -253,11 +260,13 @@ public class TestPlanService extends TestPlanBaseUtilsService { TestPlanAllocationExample allocationExample = new TestPlanAllocationExample(); allocationExample.createCriteria().andTestPlanIdIn(testPlanIds); testPlanAllocationMapper.deleteByExample(allocationExample); + + //删除测试计划报告 todo: 正式版增加接口用例报告、接口场景报告的清理 + testPlanReportService.deleteByTestPlanIds(testPlanIds); /* todo 删除计划定时任务 */ - } @@ -620,4 +629,19 @@ public class TestPlanService extends TestPlanBaseUtilsService { throw new MSException(Translator.getWithArgs("tags_length_large_than", String.valueOf(MAX_TAG_SIZE))); } } + + //通过项目删除测试计划 + public void deleteByProjectId(String projectId) { + + List testPlanIdList = extTestPlanMapper.selectIdByProjectId(projectId); + + //删除测试计划模块 + TestPlanModuleExample moduleExample = new TestPlanModuleExample(); + moduleExample.createCriteria().andProjectIdEqualTo(projectId); + testPlanModuleMapper.deleteByExample(moduleExample); + + SubListUtils.dealForSubList(testPlanIdList, SubListUtils.DEFAULT_BATCH_SIZE, dealList -> { + this.deleteByList(testPlanIdList); + }); + } } diff --git a/backend/services/test-plan/src/test/java/io/metersphere/plan/controller/TestPlanReportControllerTests.java b/backend/services/test-plan/src/test/java/io/metersphere/plan/controller/TestPlanReportControllerTests.java index 466d91a628..9e55ccb694 100644 --- a/backend/services/test-plan/src/test/java/io/metersphere/plan/controller/TestPlanReportControllerTests.java +++ b/backend/services/test-plan/src/test/java/io/metersphere/plan/controller/TestPlanReportControllerTests.java @@ -1,16 +1,26 @@ package io.metersphere.plan.controller; -import io.metersphere.plan.domain.TestPlanReport; +import io.metersphere.plan.domain.*; import io.metersphere.plan.dto.TestPlanShareInfo; import io.metersphere.plan.dto.request.*; import io.metersphere.plan.dto.response.TestPlanReportPageResponse; +import io.metersphere.plan.mapper.TestPlanReportBugMapper; +import io.metersphere.plan.mapper.TestPlanReportFunctionCaseMapper; +import io.metersphere.plan.mapper.TestPlanReportMapper; +import io.metersphere.plan.mapper.TestPlanReportSummaryMapper; +import io.metersphere.plan.service.CleanupTestPlanReportServiceImpl; +import io.metersphere.plan.service.TestPlanReportService; +import io.metersphere.sdk.constants.ProjectApplicationType; import io.metersphere.sdk.constants.ShareInfoType; +import io.metersphere.sdk.util.CommonBeanFactory; import io.metersphere.sdk.util.JSON; import io.metersphere.system.base.BaseTest; import io.metersphere.system.controller.handler.ResultHolder; import io.metersphere.system.utils.Pager; +import jakarta.annotation.Resource; import org.apache.commons.lang3.StringUtils; import org.junit.jupiter.api.*; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.jdbc.Sql; @@ -18,6 +28,7 @@ import org.springframework.test.context.jdbc.SqlConfig; import org.springframework.test.web.servlet.MvcResult; import java.nio.charset.StandardCharsets; +import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; @@ -40,6 +51,10 @@ public class TestPlanReportControllerTests extends BaseTest { private static final String GEN_AND_SHARE = "/test-plan/report/share/gen"; private static final String GET_SHARE_INFO = "/test-plan/report/share/get"; private static final String GET_SHARE_TIME = "/test-plan/report/share/get-share-time"; + @Autowired + private TestPlanReportMapper testPlanReportMapper; + @Resource + private TestPlanReportService testPlanReportService; private static String GEN_REPORT_ID; @@ -227,4 +242,41 @@ public class TestPlanReportControllerTests extends BaseTest { request.setSort(Map.of("num", "asc")); this.requestPostWithOk(GET_PLAN_REPORT_DETAIL_FUNCTIONAL_PAGE, request); } + + @Resource + private TestPlanReportSummaryMapper testPlanReportSummaryMapper; + @Resource + private TestPlanReportBugMapper testPlanReportBugMapper; + @Resource + private TestPlanReportFunctionCaseMapper testPlanReportFunctionCaseMapper; + + @Test + @Order(99) + void cleanReport() { + TestPlanReportExample reportExample = new TestPlanReportExample(); + reportExample.createCriteria().andProjectIdEqualTo("100001100001"); + List reports = testPlanReportMapper.selectByExample(reportExample); + List testPlanReportIdList = reports.stream().map(TestPlanReport::getId).toList(); + + //测试清除方法 + CleanupTestPlanReportServiceImpl cleanupTestPlanReportService = CommonBeanFactory.getBean(CleanupTestPlanReportServiceImpl.class); + cleanupTestPlanReportService.cleanReport(new HashMap<>() {{ + this.put(ProjectApplicationType.TEST_PLAN.TEST_PLAN_CLEAN_REPORT.name(), "3M"); + }}, DEFAULT_PROJECT_ID); + //清除所有数据 + testPlanReportService.cleanAndDeleteReport(testPlanReportIdList); + + TestPlanReportSummaryExample summaryExample = new TestPlanReportSummaryExample(); + summaryExample.createCriteria().andTestPlanReportIdIn(testPlanReportIdList); + + TestPlanReportFunctionCaseExample testPlanReportFunctionCaseExample = new TestPlanReportFunctionCaseExample(); + testPlanReportFunctionCaseExample.createCriteria().andTestPlanReportIdIn(testPlanReportIdList); + + TestPlanReportBugExample testPlanReportBugExample = new TestPlanReportBugExample(); + testPlanReportBugExample.createCriteria().andTestPlanReportIdIn(testPlanReportIdList); + + Assertions.assertEquals(testPlanReportSummaryMapper.countByExample(summaryExample), 0); + Assertions.assertEquals(testPlanReportFunctionCaseMapper.countByExample(testPlanReportFunctionCaseExample), 0); + Assertions.assertEquals(testPlanReportBugMapper.countByExample(testPlanReportBugExample), 0); + } } diff --git a/backend/services/test-plan/src/test/java/io/metersphere/plan/controller/TestPlanTests.java b/backend/services/test-plan/src/test/java/io/metersphere/plan/controller/TestPlanTests.java index 1922a87e31..eb20b7f410 100644 --- a/backend/services/test-plan/src/test/java/io/metersphere/plan/controller/TestPlanTests.java +++ b/backend/services/test-plan/src/test/java/io/metersphere/plan/controller/TestPlanTests.java @@ -4,22 +4,19 @@ import io.metersphere.api.domain.ApiScenario; import io.metersphere.api.domain.ApiTestCase; import io.metersphere.functional.domain.FunctionalCase; import io.metersphere.plan.constants.TestPlanResourceConfig; -import io.metersphere.plan.domain.TestPlan; -import io.metersphere.plan.domain.TestPlanConfig; -import io.metersphere.plan.domain.TestPlanExample; -import io.metersphere.plan.domain.TestPlanFunctionalCase; +import io.metersphere.plan.domain.*; import io.metersphere.plan.dto.request.*; import io.metersphere.plan.dto.response.TestPlanResourceSortResponse; +import io.metersphere.plan.mapper.ExtTestPlanMapper; import io.metersphere.plan.mapper.TestPlanMapper; -import io.metersphere.plan.service.TestPlanManagementService; -import io.metersphere.plan.service.TestPlanModuleService; -import io.metersphere.plan.service.TestPlanService; -import io.metersphere.plan.service.TestPlanTestService; +import io.metersphere.plan.mapper.TestPlanReportMapper; +import io.metersphere.plan.service.*; import io.metersphere.plan.utils.TestPlanTestUtils; import io.metersphere.project.domain.Project; import io.metersphere.project.dto.filemanagement.request.FileModuleCreateRequest; import io.metersphere.project.dto.filemanagement.request.FileModuleUpdateRequest; import io.metersphere.sdk.constants.*; +import io.metersphere.sdk.util.CommonBeanFactory; import io.metersphere.sdk.util.JSON; import io.metersphere.system.base.BaseTest; import io.metersphere.system.controller.handler.ResultHolder; @@ -27,6 +24,7 @@ import io.metersphere.system.domain.TestPlanModule; import io.metersphere.system.domain.TestPlanModuleExample; import io.metersphere.system.dto.AddProjectRequest; import io.metersphere.system.dto.sdk.BaseTreeNode; +import io.metersphere.system.dto.sdk.enums.MoveTypeEnum; import io.metersphere.system.dto.sdk.request.NodeMoveRequest; import io.metersphere.system.log.constants.OperationLogModule; import io.metersphere.system.log.constants.OperationLogType; @@ -39,7 +37,11 @@ import jakarta.annotation.Resource; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.ibatis.session.ExecutorType; +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; import org.junit.jupiter.api.*; +import org.mybatis.spring.SqlSessionUtils; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; @@ -129,6 +131,8 @@ public class TestPlanTests extends BaseTest { private static TestPlan repeatCaseTestPlan; private static final String[] PROJECT_MODULE = new String[]{"workstation", "testPlan", "bugManagement", "caseManagement", "apiTest", "uiTest", "loadTest"}; + @Resource + private ExtTestPlanMapper extTestPlanMapper; @BeforeEach public void initTestData() { @@ -495,6 +499,8 @@ public class TestPlanTests extends BaseTest { this.requestPostPermissionTest(PermissionConstants.TEST_PLAN_MODULE_READ_UPDATE, URL_POST_MODULE_UPDATE, updateRequest); } + @Resource + private SqlSessionFactory sqlSessionFactory; @Test @Order(11) @@ -555,13 +561,41 @@ public class TestPlanTests extends BaseTest { 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(); + String returnId = JSON.parseObject(JSON.toJSONString(holder.getData()), TestPlan.class).getId(); Assertions.assertNotNull(returnId); if (i == 7) { groupTestPlanId7 = returnId; } else if (i == 15) { groupTestPlanId15 = returnId; + } else if (i > 700) { + + + SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); + TestPlanReportMapper batchInsert = sqlSession.getMapper(TestPlanReportMapper.class); + //大于600要创建测试计划报告 每个测试计划创建250个报告 + for (int reportCount = 0; reportCount < 250; reportCount++) { + TestPlanReport testPlanReport = new TestPlanReport(); + testPlanReport.setId(IDGenerator.nextStr()); + testPlanReport.setTestPlanId(returnId); + testPlanReport.setName(request.getName() + "_report_" + reportCount); + testPlanReport.setCreateUser("admin"); + testPlanReport.setCreateTime(System.currentTimeMillis()); + testPlanReport.setStartTime(System.currentTimeMillis()); + testPlanReport.setEndTime(System.currentTimeMillis()); + testPlanReport.setTriggerMode("MANUAL"); + testPlanReport.setExecStatus("PENDING"); + testPlanReport.setResultStatus("SUCCESS"); + testPlanReport.setPassThreshold(99.99); + testPlanReport.setPassRate(100.00); + testPlanReport.setProjectId(project.getId()); + testPlanReport.setIntegrated(false); + testPlanReport.setDeleted(false); + batchInsert.insert(testPlanReport); + } + sqlSession.flushStatements(); + SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory); + } //操作日志检查 @@ -614,14 +648,14 @@ public class TestPlanTests extends BaseTest { MvcResult mvcResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_ADD, itemRequest); String returnStr = mvcResult.getResponse().getContentAsString(); ResultHolder holder = JSON.parseObject(returnStr, ResultHolder.class); - Assertions.assertNotNull(holder.getData().toString()); + Assertions.assertNotNull(JSON.parseObject(JSON.toJSONString(holder.getData()), TestPlan.class).getId()); itemRequest.setGroupId(groupTestPlanId15); itemRequest.setName("testPlan_group15_" + i); mvcResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_ADD, itemRequest); returnStr = mvcResult.getResponse().getContentAsString(); holder = JSON.parseObject(returnStr, ResultHolder.class); - Assertions.assertNotNull(holder.getData().toString()); + Assertions.assertNotNull(JSON.parseObject(JSON.toJSONString(holder.getData()), TestPlan.class).getId()); } /* @@ -1020,9 +1054,11 @@ public class TestPlanTests extends BaseTest { //将第30个移动到第一位之前 ResourceSortRequest request = new ResourceSortRequest(); request.setTestPlanId(repeatCaseTestPlan.getId()); - request.setDragNodeId(funcList.get(29).getId()); - request.setDropNodeId(funcList.get(0).getId()); - request.setDropPosition(-1); + request.setProjectId(DEFAULT_PROJECT_ID); + request.setMoveId(funcList.get(29).getId()); + request.setTargetId(funcList.get(0).getId()); + request.setMoveMode(MoveTypeEnum.AFTER.name()); + //先测试一下没有开启模块时能否使用 testPlanTestService.removeProjectModule(project, PROJECT_MODULE, "caseManagement"); @@ -1035,42 +1071,42 @@ public class TestPlanTests extends BaseTest { TestPlanResourceSortResponse response = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), TestPlanResourceSortResponse.class); Assertions.assertEquals(response.getSortNodeNum(), 1); funcList = testPlanTestService.selectTestPlanFunctionalCaseByTestPlanId(repeatCaseTestPlan.getId()); - Assertions.assertEquals(funcList.get(0).getId(), request.getDragNodeId()); - Assertions.assertEquals(funcList.get(1).getId(), request.getDropNodeId()); + Assertions.assertEquals(funcList.get(0).getId(), request.getMoveId()); + Assertions.assertEquals(funcList.get(1).getId(), request.getTargetId()); LOG_CHECK_LIST.add( - new CheckLogModel(request.getDragNodeId(), OperationLogType.UPDATE, URL_POST_RESOURCE_FUNCTIONAL_CASE_SORT) + new CheckLogModel(request.getMoveId(), OperationLogType.UPDATE, URL_POST_RESOURCE_FUNCTIONAL_CASE_SORT) ); //将这时的第30个放到第一位之后 - request.setDragNodeId(funcList.get(29).getId()); - request.setDropNodeId(funcList.get(0).getId()); - request.setDropPosition(1); + request.setMoveId(funcList.get(29).getId()); + request.setTargetId(funcList.get(0).getId()); + request.setMoveMode(MoveTypeEnum.BEFORE.name()); result = this.requestPostWithOkAndReturn(URL_POST_RESOURCE_FUNCTIONAL_CASE_SORT, request); resultHolder = JSON.parseObject(result.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class); response = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), TestPlanResourceSortResponse.class); Assertions.assertEquals(response.getSortNodeNum(), 1); funcList = testPlanTestService.selectTestPlanFunctionalCaseByTestPlanId(repeatCaseTestPlan.getId()); - Assertions.assertEquals(funcList.get(0).getId(), request.getDropNodeId()); - Assertions.assertEquals(funcList.get(1).getId(), request.getDragNodeId()); + Assertions.assertEquals(funcList.get(0).getId(), request.getTargetId()); + Assertions.assertEquals(funcList.get(1).getId(), request.getMoveId()); LOG_CHECK_LIST.add( - new CheckLogModel(request.getDragNodeId(), OperationLogType.UPDATE, URL_POST_RESOURCE_FUNCTIONAL_CASE_SORT) + new CheckLogModel(request.getMoveId(), OperationLogType.UPDATE, URL_POST_RESOURCE_FUNCTIONAL_CASE_SORT) ); //再将这时的第30个放到第一位之后,但是第一个的pos为2,检查能否触发ref操作 - request.setDragNodeId(funcList.get(29).getId()); - request.setDropNodeId(funcList.get(0).getId()); - request.setDropPosition(-1); + request.setMoveId(funcList.get(29).getId()); + request.setTargetId(funcList.get(0).getId()); + request.setMoveMode(MoveTypeEnum.AFTER.name()); testPlanTestService.setResourcePos(funcList.get(0).getId(), TestPlanResourceConstants.RESOURCE_FUNCTIONAL_CASE, 2); result = this.requestPostWithOkAndReturn(URL_POST_RESOURCE_FUNCTIONAL_CASE_SORT, request); resultHolder = JSON.parseObject(result.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class); response = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), TestPlanResourceSortResponse.class); Assertions.assertEquals(response.getSortNodeNum(), 1); funcList = testPlanTestService.selectTestPlanFunctionalCaseByTestPlanId(repeatCaseTestPlan.getId()); - Assertions.assertEquals(funcList.get(0).getId(), request.getDragNodeId()); - Assertions.assertEquals(funcList.get(1).getId(), request.getDropNodeId()); + Assertions.assertEquals(funcList.get(0).getId(), request.getMoveId()); + Assertions.assertEquals(funcList.get(1).getId(), request.getTargetId()); LOG_CHECK_LIST.add( - new CheckLogModel(request.getDragNodeId(), OperationLogType.UPDATE, URL_POST_RESOURCE_FUNCTIONAL_CASE_SORT) + new CheckLogModel(request.getMoveId(), OperationLogType.UPDATE, URL_POST_RESOURCE_FUNCTIONAL_CASE_SORT) ); //反例:测试计划为空 @@ -1081,23 +1117,18 @@ public class TestPlanTests extends BaseTest { this.requestPost(URL_POST_RESOURCE_FUNCTIONAL_CASE_SORT, request).andExpect(status().is5xxServerError()); //反例:拖拽的节点不存在 request.setTestPlanId(repeatCaseTestPlan.getId()); - request.setDragNodeId(null); - this.requestPost(URL_POST_RESOURCE_FUNCTIONAL_CASE_SORT, request).andExpect(status().is5xxServerError()); + request.setMoveId(null); + this.requestPost(URL_POST_RESOURCE_FUNCTIONAL_CASE_SORT, request).andExpect(status().isBadRequest()); //反例:目标节点不存在 - request.setDragNodeId(funcList.get(29).getId()); - request.setDropNodeId(null); - this.requestPost(URL_POST_RESOURCE_FUNCTIONAL_CASE_SORT, request).andExpect(status().is5xxServerError()); + request.setMoveId(funcList.get(29).getId()); + request.setTargetId(null); + this.requestPost(URL_POST_RESOURCE_FUNCTIONAL_CASE_SORT, request).andExpect(status().isBadRequest()); //反例: 节点重复 - request.setDropNodeId(request.getDragNodeId()); - this.requestPost(URL_POST_RESOURCE_FUNCTIONAL_CASE_SORT, request).andExpect(status().is5xxServerError()); - //反例: dropPosition取值范围不对 - request.setDragNodeId(funcList.get(29).getId()); - request.setDropNodeId(funcList.get(0).getId()); - request.setDropPosition(0); + request.setTargetId(request.getMoveId()); this.requestPost(URL_POST_RESOURCE_FUNCTIONAL_CASE_SORT, request).andExpect(status().is5xxServerError()); //测试权限 - request.setDropPosition(1); + request.setMoveMode(MoveTypeEnum.BEFORE.name()); this.requestPostPermissionTest(PermissionConstants.TEST_PLAN_READ_UPDATE, URL_POST_RESOURCE_FUNCTIONAL_CASE_SORT, request); } @@ -1362,10 +1393,10 @@ public class TestPlanTests extends BaseTest { @Test @Order(101) public void deleteTestPlanTest() throws Exception { - int allDataInDB = 999 + 40; if (StringUtils.isEmpty(groupTestPlanId7)) { this.testPlanAddTest(); } + int allDataInDB = 999 + 40; //根据id删除 (删除 第61这1个) List testPlanList = testPlanTestService.selectByProjectIdAndNames(project.getId(), @@ -1445,12 +1476,17 @@ public class TestPlanTests extends BaseTest { request.setType("ALL"); this.requestPostWithOk(URL_POST_TEST_PLAN_BATCH_DELETE, request); testPlanTestService.checkDataCount(project.getId(), allDataInDB); + + TestPlanExample deleteExample = new TestPlanExample(); + deleteExample.createCriteria().andProjectIdEqualTo(project.getId()); + } @Test @Order(102) public void deleteModuleTest() throws Exception { this.preliminaryTree(); + List testPlanIdList = extTestPlanMapper.selectIdByProjectId(project.getId()); // 删除没有文件的节点a1-b1-c1 检查是否级联删除根节点 BaseTreeNode a1b1Node = TestPlanTestUtils.getNodeByName(this.getFileModuleTreeNode(), "a1-b1"); @@ -1481,18 +1517,38 @@ public class TestPlanTests extends BaseTest { this.requestGet(String.format(URL_GET_MODULE_DELETE, IDGenerator.nextNum())).andExpect(status().is5xxServerError()); // 测试删除根节点(根节点无法删除) this.requestGet(String.format(URL_GET_MODULE_DELETE, ModuleConstants.DEFAULT_NODE_ID)).andExpect(status().is5xxServerError()); - ; //service层判断:测试删除空集合 testPlanModuleService.deleteModule(new ArrayList<>(), project.getId(), null, null, null); - //service层判断:测试删除项目 - // testPlanModuleService.deleteResources(project.getId()); - //判断权限 this.requestGetPermissionTest(PermissionConstants.TEST_PLAN_MODULE_READ_DELETE, (String.format(URL_GET_MODULE_DELETE, IDGenerator.nextNum()))); + + //删除当前项目下的所有测试计划相关的数据 + CleanupPlanResourceService cleanupPlanResourceService = CommonBeanFactory.getBean(CleanupPlanResourceService.class); + cleanupPlanResourceService.deleteResources(project.getId()); + + //检查资源是否为0 + testPlanTestService.checkDataEmpty(testPlanIdList, project.getId()); } + @Resource + private TestPlanFunctionalCaseService testPlanFunctionalCaseService; + @Resource + private TestPlanApiCaseService testPlanApiCaseService; + @Resource + private TestPlanApiScenarioService testPlanApiScenarioService; + @Resource + private TestPlanBugService testPlanBugService; + + @Test + public void emptyMethodTest() throws Exception { + // 暂时没用到的空方法的访问 + testPlanApiCaseService.getNextOrder(DEFAULT_PROJECT_ID); + testPlanApiScenarioService.getNextOrder(DEFAULT_PROJECT_ID); + testPlanBugService.getNextOrder(DEFAULT_PROJECT_ID); + testPlanFunctionalCaseService.getNextOrder(DEFAULT_PROJECT_ID); + } private void checkModuleIsEmpty(String id) { TestPlanModuleExample example = new TestPlanModuleExample(); example.createCriteria().andParentIdEqualTo(id); @@ -1687,7 +1743,7 @@ public class TestPlanTests extends BaseTest { 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(); + String returnId = JSON.parseObject(JSON.toJSONString(holder.getData()), TestPlan.class).getId(); Assertions.assertNotNull(returnId); TestPlanUpdateRequest updateRequest = new TestPlanUpdateRequest(); diff --git a/backend/services/test-plan/src/test/java/io/metersphere/plan/service/TestPlanTestService.java b/backend/services/test-plan/src/test/java/io/metersphere/plan/service/TestPlanTestService.java index 9f4554d053..99e2347298 100644 --- a/backend/services/test-plan/src/test/java/io/metersphere/plan/service/TestPlanTestService.java +++ b/backend/services/test-plan/src/test/java/io/metersphere/plan/service/TestPlanTestService.java @@ -15,6 +15,8 @@ import io.metersphere.project.domain.Project; import io.metersphere.project.mapper.ProjectMapper; import io.metersphere.sdk.constants.*; import io.metersphere.sdk.util.JSON; +import io.metersphere.sdk.util.SubListUtils; +import io.metersphere.system.domain.TestPlanModuleExample; import io.metersphere.system.uid.IDGenerator; import io.metersphere.system.uid.NumGenerator; import jakarta.annotation.Resource; @@ -37,6 +39,12 @@ public class TestPlanTestService { @Resource private FunctionalCaseMapper functionalCaseMapper; @Resource + private TestPlanFollowerMapper testPlanFollowerMapper; + @Resource + private TestPlanAllocationMapper testPlanAllocationMapper; + @Resource + private TestPlanReportMapper testPlanReportMapper; + @Resource private TestPlanFunctionalCaseMapper testPlanFunctionalCaseMapper; @Resource private TestPlanApiCaseMapper testPlanApiCaseMapper; @@ -379,4 +387,46 @@ public class TestPlanTestService { testPlanApiScenarioMapper.updateByPrimaryKeySelective(updateCase); } } + + public void checkDataEmpty(List testPlanIdList, String projectId) { + SubListUtils.dealForSubList(testPlanIdList, SubListUtils.DEFAULT_BATCH_SIZE, (subList) -> { + TestPlanExample testPlanExample = new TestPlanExample(); + testPlanExample.createCriteria().andIdIn(subList); + Assertions.assertEquals(testPlanMapper.countByExample(testPlanExample), 0); + + TestPlanModuleExample testPlanModuleExample = new TestPlanModuleExample(); + testPlanModuleExample.createCriteria().andProjectIdEqualTo(projectId); + Assertions.assertEquals(testPlanMapper.countByExample(testPlanExample), 0); + + TestPlanConfigExample testPlanConfigExample = new TestPlanConfigExample(); + testPlanConfigExample.createCriteria().andTestPlanIdIn(subList); + Assertions.assertEquals(testPlanConfigMapper.countByExample(testPlanConfigExample), 0); + + TestPlanFunctionalCaseExample testPlanFunctionalCaseExample = new TestPlanFunctionalCaseExample(); + testPlanFunctionalCaseExample.createCriteria().andTestPlanIdIn(subList); + Assertions.assertEquals(testPlanFunctionalCaseMapper.countByExample(testPlanFunctionalCaseExample), 0); + + TestPlanApiCaseExample testPlanApiCaseExample = new TestPlanApiCaseExample(); + testPlanApiCaseExample.createCriteria().andTestPlanIdIn(subList); + Assertions.assertEquals(testPlanApiCaseMapper.countByExample(testPlanApiCaseExample), 0); + + TestPlanApiScenarioExample testPlanApiScenarioExample = new TestPlanApiScenarioExample(); + testPlanApiScenarioExample.createCriteria().andTestPlanIdIn(subList); + Assertions.assertEquals(testPlanApiScenarioMapper.countByExample(testPlanApiScenarioExample), 0); + + TestPlanFollowerExample testPlanFollowerExample = new TestPlanFollowerExample(); + testPlanFollowerExample.createCriteria().andTestPlanIdIn(subList); + Assertions.assertEquals(testPlanFollowerMapper.countByExample(testPlanFollowerExample), 0); + + TestPlanAllocationExample testPlanAllocationExample = new TestPlanAllocationExample(); + testPlanAllocationExample.createCriteria().andTestPlanIdIn(subList); + Assertions.assertEquals(testPlanAllocationMapper.countByExample(testPlanAllocationExample), 0); + + TestPlanReportExample testPlanReportExample = new TestPlanReportExample(); + testPlanReportExample.createCriteria().andTestPlanIdIn(subList); + Assertions.assertEquals(testPlanReportMapper.countByExample(testPlanReportExample), 0); + + + }); + } }