feat(测试计划): 编写测试计划资源清理方法

This commit is contained in:
Jianguo-Genius 2024-05-16 19:39:17 +08:00 committed by 建国
parent 1e690a5f1e
commit aa9101c795
23 changed files with 443 additions and 100 deletions

View File

@ -1,25 +1,30 @@
package io.metersphere.sdk.util; package io.metersphere.sdk.util;
import org.apache.commons.collections4.CollectionUtils;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
public class SubListUtils { public class SubListUtils {
public static int DEFAULT_BATCH_SIZE = 200;
/** /**
* 将较长的数组截断成较短的数组进行批处理 * 将较长的数组截断成较短的数组进行批处理
*/ */
public static <T> void dealForSubList(List<T> totalList, Integer batchSize, Consumer<List<T>> subFunc) { public static <T> void dealForSubList(List<T> totalList, int batchSize, Consumer<List<T>> subFunc) {
int count = totalList.size(); if (CollectionUtils.isEmpty(totalList)) {
int iteratorCount = count / batchSize; return;
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<T> subList = totalList.subList(startIndex, endIndex); List<T> dealList = new ArrayList<>(totalList);
while (dealList.size() > batchSize) {
List<T> subList = dealList.subList(0, batchSize);
subFunc.accept(subList); subFunc.accept(subList);
dealList = dealList.subList(subList.size(), dealList.size());
}
if (CollectionUtils.isNotEmpty(dealList)) {
subFunc.accept(dealList);
} }
} }

View File

@ -74,7 +74,7 @@ public class TestPlanController {
@RequiresPermissions(PermissionConstants.TEST_PLAN_READ_ADD) @RequiresPermissions(PermissionConstants.TEST_PLAN_READ_ADD)
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project") @CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
@SendNotice(taskType = NoticeConstants.TaskType.TEST_PLAN_TASK, event = NoticeConstants.Event.CREATE, target = "#targetClass.sendAddNotice(#request)", targetClass = TestPlanSendNoticeService.class) @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)); 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()); return testPlanService.add(request, SessionUtils.getUserId(), "/test-plan/add", HttpMethodConstants.POST.name());
} }

View File

@ -49,7 +49,6 @@ public class TestPlanFunctionalCaseController {
@Resource @Resource
private TestPlanFunctionalCaseService testPlanFunctionalCaseService; private TestPlanFunctionalCaseService testPlanFunctionalCaseService;
@PostMapping(value = "/sort") @PostMapping(value = "/sort")
@Operation(summary = "测试计划功能用例-功能用例拖拽排序") @Operation(summary = "测试计划功能用例-功能用例拖拽排序")
@RequiresPermissions(PermissionConstants.TEST_PLAN_READ_UPDATE) @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())); return testPlanFunctionalCaseService.sortNode(request, new LogInsertModule(SessionUtils.getUserId(), "/test-plan/functional/case/sort", HttpMethodConstants.POST.name()));
} }
@PostMapping("/page") @PostMapping("/page")
@Operation(summary = "测试计划-已关联功能用例分页查询") @Operation(summary = "测试计划-已关联功能用例分页查询")
@RequiresPermissions(PermissionConstants.TEST_PLAN_READ) @RequiresPermissions(PermissionConstants.TEST_PLAN_READ)
@ -69,7 +67,6 @@ public class TestPlanFunctionalCaseController {
return PageUtils.setPageInfo(page, testPlanFunctionalCaseService.getFunctionalCasePage(request, false)); return PageUtils.setPageInfo(page, testPlanFunctionalCaseService.getFunctionalCasePage(request, false));
} }
@GetMapping("/tree/{testPlanId}") @GetMapping("/tree/{testPlanId}")
@Operation(summary = "测试计划-已关联功能用例列表模块树") @Operation(summary = "测试计划-已关联功能用例列表模块树")
@RequiresPermissions(PermissionConstants.TEST_PLAN_READ) @RequiresPermissions(PermissionConstants.TEST_PLAN_READ)

View File

@ -73,7 +73,7 @@ public class TestPlanReportController {
@Log(type = OperationLogType.DELETE, expression = "#msClass.deleteLog(#id)", msClass = TestPlanReportLogService.class) @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) @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) { public void delete(@PathVariable String id) {
testPlanReportService.delete(id); testPlanReportService.setReportDelete(id);
} }
@PostMapping("/batch-delete") @PostMapping("/batch-delete")
@ -81,7 +81,7 @@ public class TestPlanReportController {
@RequiresPermissions(PermissionConstants.TEST_PLAN_REPORT_READ_DELETE) @RequiresPermissions(PermissionConstants.TEST_PLAN_REPORT_READ_DELETE)
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project") @CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
public void batchDelete(@Validated @RequestBody TestPlanReportBatchRequest request) { public void batchDelete(@Validated @RequestBody TestPlanReportBatchRequest request) {
testPlanReportService.batchDelete(request, SessionUtils.getUserId()); testPlanReportService.batchSetReportDelete(request, SessionUtils.getUserId());
} }
@PostMapping("/gen") @PostMapping("/gen")

View File

@ -1,23 +1,14 @@
package io.metersphere.plan.dto.request; package io.metersphere.plan.dto.request;
import io.metersphere.system.dto.sdk.request.PosRequest;
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 lombok.Data; import lombok.Data;
@Data @Data
public class ResourceSortRequest { public class ResourceSortRequest extends PosRequest {
@Schema(description = "测试计划ID") @Schema(description = "测试计划ID")
@NotBlank(message = "{test_plan.id.not_blank}") @NotBlank(message = "{test_plan.id.not_blank}")
private String testPlanId; private String testPlanId;
@Schema(description = "拖拽的节点ID")
private String dragNodeId;
@Schema(description = "目标节点")
private String dropNodeId;
@Schema(description = "放入的位置(取值:-1,0,1。 -1dropNodeId节点之前。 0:dropNodeId节点内。 1dropNodeId节点后", requiredMode = Schema.RequiredMode.REQUIRED)
private int dropPosition;
} }

View File

@ -20,6 +20,8 @@ public interface ExtTestPlanFunctionalCaseMapper {
List<String> selectIdByTestPlanIdOrderByPos(String testPlanId); List<String> selectIdByTestPlanIdOrderByPos(String testPlanId);
List<String> selectIdByTestPlanIds(@Param("testPlanIds") List<String> testPlanIdList);
Long getMaxPosByTestPlanId(String testPlanId); Long getMaxPosByTestPlanId(String testPlanId);
List<String> getIdByParam(ResourceSelectParam resourceSelectParam); List<String> getIdByParam(ResourceSelectParam resourceSelectParam);

View File

@ -13,6 +13,14 @@
WHERE test_plan_id = #{testPlanId} WHERE test_plan_id = #{testPlanId}
ORDER BY pos ASC ORDER BY pos ASC
</select> </select>
<select id="selectIdByTestPlanIds" resultType="java.lang.String">
SELECT id
FROM test_plan_functional_case
WHERE test_plan_id IN
<foreach collection="testPlanIds" item="item" index="index" open="(" close=")" separator=",">
#{item}
</foreach>
</select>
<select id="getMaxPosByTestPlanId" resultType="java.lang.Long"> <select id="getMaxPosByTestPlanId" resultType="java.lang.Long">
SELECT max(pos) SELECT max(pos)
FROM test_plan_functional_case FROM test_plan_functional_case

View File

@ -36,4 +36,6 @@ public interface ExtTestPlanMapper {
List<TestPlan> getTagsByIds(@Param("ids") List<String> ids); List<TestPlan> getTagsByIds(@Param("ids") List<String> ids);
void batchUpdate(@Param("testPlan") TestPlan testPlan, @Param("ids") List<String> ids); void batchUpdate(@Param("testPlan") TestPlan testPlan, @Param("ids") List<String> ids);
List<String> selectIdByProjectId(String projectId);
} }

View File

@ -385,6 +385,11 @@
#{id} #{id}
</foreach> </foreach>
</select> </select>
<select id="selectIdByProjectId" resultType="java.lang.String">
SELECT id
FROM test_plan
WHERE project_id = #{0}
</select>
<update id="batchUpdate"> <update id="batchUpdate">

View File

@ -62,4 +62,10 @@ public interface ExtTestPlanReportMapper {
* @return 关联的用例集合 * @return 关联的用例集合
*/ */
List<FunctionalCasePageDTO> listReportFunctionalCases(@Param("request")TestPlanReportDetailPageRequest request); List<FunctionalCasePageDTO> listReportFunctionalCases(@Param("request")TestPlanReportDetailPageRequest request);
long countReportByTime(@Param("time") long timeMills, @Param("projectId") String projectId);
List<String> selectReportIdByProjectIdAndTime(@Param("time") long timeMills, @Param("projectId") String projectId);
List<String> selectReportIdTestPlanIds(@Param("testPlanIds") List<String> testPlanIds);
} }

View File

@ -51,6 +51,30 @@
#{id} #{id}
</foreach> </foreach>
</select> </select>
<select id="countReportByTime" resultType="java.lang.Long">
select count(report.id)
from test_plan_report report
inner join test_plan_report_summary summary
on report.id = summary.test_plan_report_id = report.id
where report.start_time &lt;= #{time}
and report.project_id = #{projectId}
</select>
<select id="selectReportIdByProjectIdAndTime" resultType="java.lang.String">
select report.id
from test_plan_report report
inner join test_plan_report_summary summary
on report.id = summary.test_plan_report_id = report.id
where report.project_id = #{projectId}
and report.start_time = #{time}
</select>
<select id="selectReportIdTestPlanIds" resultType="java.lang.String">
select report.id
from test_plan_report report
where report.test_plan_id IN
<foreach collection="testPlanIds" item="testPlanId" open="(" close=")" separator=",">
#{testPlanId}
</foreach>
</select>
<sql id="queryWhereCondition"> <sql id="queryWhereCondition">
<where> <where>

View File

@ -2,14 +2,19 @@ package io.metersphere.plan.service;
import io.metersphere.sdk.util.LogUtils; import io.metersphere.sdk.util.LogUtils;
import io.metersphere.system.service.CleanupProjectResourceService; import io.metersphere.system.service.CleanupProjectResourceService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@Component @Component
public class CleanupPlanResourceService implements CleanupProjectResourceService { public class CleanupPlanResourceService implements CleanupProjectResourceService {
@Resource
private TestPlanService testPlanService;
@Override @Override
public void deleteResources(String projectId) { public void deleteResources(String projectId) {
LogUtils.info("删除当前项目[" + projectId + "]相关测试计划资源"); LogUtils.info("删除当前项目[" + projectId + "]的测试计划资源开始");
testPlanService.deleteByProjectId(projectId);
LogUtils.info("删除当前项目[" + projectId + "]的测试计划资源结束");
} }
} }

View File

@ -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<String, String> map, String projectId) {
LogUtils.info("清理当前项目[" + projectId + "]相关测试计划报告开始:");
String expr = map.get(ProjectApplicationType.TEST_PLAN.TEST_PLAN_CLEAN_REPORT.name());
long timeMills = getCleanDate(expr);
List<String> ids = extTestPlanReportMapper.selectReportIdByProjectIdAndTime(timeMills, projectId);
LogUtils.info("清理当前项目[" + projectId + "]相关测试计划报告,共[" + ids.size() + "]条");
testPlanReportService.cleanAndDeleteReport(ids);
LogUtils.info("清理当前项目[" + projectId + "]相关测试计划报告结束!");
}
}

View File

@ -27,6 +27,11 @@ public class TestPlanApiCaseService extends TestPlanResourceService {
return testPlanApiCaseMapper.deleteByExample(example); return testPlanApiCaseMapper.deleteByExample(example);
} }
@Override
public long getNextOrder(String projectId) {
return 0;
}
@Override @Override
public void updatePos(String id, long pos) { public void updatePos(String id, long pos) {
// TODO // TODO

View File

@ -27,6 +27,11 @@ public class TestPlanApiScenarioService extends TestPlanResourceService {
return testPlanApiScenarioMapper.deleteByExample(example); return testPlanApiScenarioMapper.deleteByExample(example);
} }
@Override
public long getNextOrder(String projectId) {
return 0;
}
@Override @Override
public void updatePos(String id, long pos) { public void updatePos(String id, long pos) {
// TODO // TODO

View File

@ -70,6 +70,10 @@ public class TestPlanBugService extends TestPlanResourceService {
} }
@Override
public long getNextOrder(String projectId) {
return 0;
}
@Override @Override
public void updatePos(String id, long pos) { public void updatePos(String id, long pos) {

View File

@ -128,12 +128,24 @@ public class TestPlanFunctionalCaseService extends TestPlanResourceService {
@Override @Override
public int deleteBatchByTestPlanId(List<String> testPlanIdList) { public int deleteBatchByTestPlanId(List<String> testPlanIdList) {
TestPlanFunctionalCaseExample example = new TestPlanFunctionalCaseExample(); TestPlanFunctionalCaseExample testPlanFunctionalCaseExample = new TestPlanFunctionalCaseExample();
testPlanFunctionalCaseExample.createCriteria().andTestPlanIdIn(testPlanIdList);
testPlanFunctionalCaseMapper.deleteByExample(testPlanFunctionalCaseExample);
// 取消关联用例需同步删除计划-用例缺陷关系表
BugRelationCaseExample example = new BugRelationCaseExample();
example.createCriteria().andTestPlanIdIn(testPlanIdList); 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 @Override
public void updatePos(String id, long pos) { public void updatePos(String id, long pos) {
extTestPlanFunctionalCaseMapper.updatePos(id, pos); extTestPlanFunctionalCaseMapper.updatePos(id, pos);
@ -164,20 +176,21 @@ public class TestPlanFunctionalCaseService extends TestPlanResourceService {
} }
public TestPlanResourceSortResponse sortNode(ResourceSortRequest request, LogInsertModule logInsertModule) { 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()); TestPlan testPlan = testPlanMapper.selectByPrimaryKey(request.getTestPlanId());
if (dragNode == null) { if (dragNode == null) {
throw new MSException(Translator.get("test_plan.drag.node.error")); throw new MSException(Translator.get("test_plan.drag.node.error"));
} }
TestPlanResourceSortResponse response = new TestPlanResourceSortResponse(); TestPlanResourceSortResponse response = new TestPlanResourceSortResponse();
AssociationNodeSortDTO sortDTO = super.getNodeSortDTO( AssociationNodeSortDTO sortDTO = super.getNodeSortDTO(
request, super.getNodeMoveRequest(request),
request.getTestPlanId(),
extTestPlanFunctionalCaseMapper::selectDragInfoById, extTestPlanFunctionalCaseMapper::selectDragInfoById,
extTestPlanFunctionalCaseMapper::selectNodeByPosOperator extTestPlanFunctionalCaseMapper::selectNodeByPosOperator
); );
super.sort(sortDTO); super.sort(sortDTO);
response.setSortNodeNum(1); 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; return response;
} }

View File

@ -70,6 +70,10 @@ public class TestPlanReportService {
private TestPlanReportSummaryMapper testPlanReportSummaryMapper; private TestPlanReportSummaryMapper testPlanReportSummaryMapper;
@Resource @Resource
private TestPlanFunctionalCaseMapper testPlanFunctionalCaseMapper; 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); TestPlanReport report = checkReport(id);
report.setDeleted(true); report.setDeleted(true);
testPlanReportMapper.updateByPrimaryKeySelective(report); testPlanReportMapper.updateByPrimaryKeySelective(report);
@ -111,23 +115,72 @@ public class TestPlanReportService {
* *
* @param request 请求参数 * @param request 请求参数
*/ */
public void batchDelete(TestPlanReportBatchRequest request, String userId) { public void batchSetReportDelete(TestPlanReportBatchRequest request, String userId) {
List<String> batchIds = getBatchIds(request); List<String> batchIds = getBatchIds(request);
User user = userMapper.selectByPrimaryKey(userId); User user = userMapper.selectByPrimaryKey(userId);
if (CollectionUtils.isNotEmpty(batchIds)) { if (CollectionUtils.isNotEmpty(batchIds)) {
SubListUtils.dealForSubList(batchIds, 500, subList -> { SubListUtils.dealForSubList(batchIds, SubListUtils.DEFAULT_BATCH_SIZE, subList -> {
TestPlanReportExample example = new TestPlanReportExample(); TestPlanReportExample example = new TestPlanReportExample();
example.createCriteria().andIdIn(subList); example.createCriteria().andIdIn(subList);
TestPlanReport testPlanReport = new TestPlanReport(); TestPlanReport testPlanReport = new TestPlanReport();
testPlanReport.setDeleted(true); testPlanReport.setDeleted(true);
testPlanReportMapper.updateByExampleSelective(testPlanReport, example); testPlanReportMapper.updateByExampleSelective(testPlanReport, example);
testPlanReportLogService.batchDeleteLog(subList, userId, request.getProjectId()); testPlanReportLogService.batchDeleteLog(subList, userId, request.getProjectId());
testPlanReportNoticeService.batchSendNotice(subList, user, request.getProjectId(), NoticeConstants.Event.DELETE); testPlanReportNoticeService.batchSendNotice(subList, user, request.getProjectId(), NoticeConstants.Event.DELETE);
}); });
} }
} }
/**
* 清空测试计划报告包括summary
*
* @param reportIdList
*/
public void cleanAndDeleteReport(List<String> 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<String> testPlanIds) {
if (CollectionUtils.isNotEmpty(testPlanIds)) {
List<String> 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<String> 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 请求参数 * @param request 请求参数

View File

@ -6,15 +6,16 @@ import io.metersphere.plan.dto.AssociationNodeSortDTO;
import io.metersphere.plan.dto.ResourceLogInsertModule; import io.metersphere.plan.dto.ResourceLogInsertModule;
import io.metersphere.plan.dto.TestPlanResourceAssociationParam; import io.metersphere.plan.dto.TestPlanResourceAssociationParam;
import io.metersphere.plan.dto.request.BasePlanCaseBatchRequest; 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.dto.response.TestPlanAssociationResponse;
import io.metersphere.plan.mapper.TestPlanMapper; import io.metersphere.plan.mapper.TestPlanMapper;
import io.metersphere.project.dto.ModuleSortCountResultDTO; import io.metersphere.project.dto.ModuleSortCountResultDTO;
import io.metersphere.project.dto.NodeSortQueryParam; import io.metersphere.project.dto.NodeSortQueryParam;
import io.metersphere.project.service.MoveNodeService;
import io.metersphere.project.utils.NodeSortUtils; import io.metersphere.project.utils.NodeSortUtils;
import io.metersphere.sdk.exception.MSException; import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.Translator; import io.metersphere.sdk.util.Translator;
import io.metersphere.system.dto.LogInsertModule; import io.metersphere.system.dto.LogInsertModule;
import io.metersphere.system.dto.sdk.request.NodeMoveRequest;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -29,7 +30,7 @@ import java.util.function.Function;
//测试计划关联表 通用方法 //测试计划关联表 通用方法
@Service @Service
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public abstract class TestPlanResourceService { public abstract class TestPlanResourceService extends MoveNodeService {
@Resource @Resource
private TestPlanMapper testPlanMapper; private TestPlanMapper testPlanMapper;
@ -80,7 +81,7 @@ public abstract class TestPlanResourceService {
* @param selectPosNodeFunc 通过parentId和pos运算符查询节点的函数 * @param selectPosNodeFunc 通过parentId和pos运算符查询节点的函数
* @return * @return
*/ */
public AssociationNodeSortDTO getNodeSortDTO(ResourceSortRequest request, Function<String, AssociationNode> selectIdNodeFunc, Function<NodeSortQueryParam, AssociationNode> selectPosNodeFunc) { public AssociationNodeSortDTO getNodeSortDTO(NodeMoveRequest request, String testPlanId, Function<String, AssociationNode> selectIdNodeFunc, Function<NodeSortQueryParam, AssociationNode> selectPosNodeFunc) {
if (StringUtils.equals(request.getDragNodeId(), request.getDropNodeId())) { if (StringUtils.equals(request.getDragNodeId(), request.getDropNodeId())) {
//两种节点不能一样 //两种节点不能一样
throw new MSException(Translator.get("invalid_parameter") + ": drag node and drop node"); throw new MSException(Translator.get("invalid_parameter") + ": drag node and drop node");
@ -104,7 +105,7 @@ public abstract class TestPlanResourceService {
previousNode = dropNode; previousNode = dropNode;
NodeSortQueryParam sortParam = new NodeSortQueryParam(); NodeSortQueryParam sortParam = new NodeSortQueryParam();
sortParam.setParentId(request.getTestPlanId()); sortParam.setParentId(testPlanId);
sortParam.setPos(previousNode.getPos()); sortParam.setPos(previousNode.getPos());
sortParam.setOperator(MOVE_POS_OPERATOR_MORE); sortParam.setOperator(MOVE_POS_OPERATOR_MORE);
nextNode = selectPosNodeFunc.apply(sortParam); nextNode = selectPosNodeFunc.apply(sortParam);
@ -113,14 +114,14 @@ public abstract class TestPlanResourceService {
nextNode = dropNode; nextNode = dropNode;
NodeSortQueryParam sortParam = new NodeSortQueryParam(); NodeSortQueryParam sortParam = new NodeSortQueryParam();
sortParam.setPos(nextNode.getPos()); sortParam.setPos(nextNode.getPos());
sortParam.setParentId(request.getTestPlanId()); sortParam.setParentId(testPlanId);
sortParam.setOperator(MOVE_POS_OPERATOR_LESS); sortParam.setOperator(MOVE_POS_OPERATOR_LESS);
previousNode = selectPosNodeFunc.apply(sortParam); previousNode = selectPosNodeFunc.apply(sortParam);
} else { } else {
throw new MSException(Translator.get("invalid_parameter") + ": dropPosition"); throw new MSException(Translator.get("invalid_parameter") + ": dropPosition");
} }
return new AssociationNodeSortDTO(request.getTestPlanId(), dragNode, previousNode, nextNode); return new AssociationNodeSortDTO(testPlanId, dragNode, previousNode, nextNode);
} }
//排序 //排序

View File

@ -11,8 +11,10 @@ import io.metersphere.sdk.constants.TestPlanConstants;
import io.metersphere.sdk.exception.MSException; import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.BeanUtils; import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.CommonBeanFactory; import io.metersphere.sdk.util.CommonBeanFactory;
import io.metersphere.sdk.util.SubListUtils;
import io.metersphere.sdk.util.Translator; import io.metersphere.sdk.util.Translator;
import io.metersphere.system.domain.ScheduleExample; import io.metersphere.system.domain.ScheduleExample;
import io.metersphere.system.domain.TestPlanModuleExample;
import io.metersphere.system.domain.User; import io.metersphere.system.domain.User;
import io.metersphere.system.log.constants.OperationLogType; import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.mapper.ScheduleMapper; import io.metersphere.system.mapper.ScheduleMapper;
@ -83,10 +85,10 @@ public class TestPlanService extends TestPlanBaseUtilsService {
* @param requestMethod * @param requestMethod
* @return * @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); TestPlan testPlan = savePlanDTO(testPlanCreateRequest, operator, null);
testPlanLogService.saveAddLog(testPlan, operator, requestUrl, requestMethod); testPlanLogService.saveAddLog(testPlan, operator, requestUrl, requestMethod);
return testPlan.getId(); return testPlan;
} }
@ -150,7 +152,8 @@ public class TestPlanService extends TestPlanBaseUtilsService {
} else { } else {
testPlanMapper.deleteByPrimaryKey(id); 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); testPlanLogService.saveDeleteLog(testPlan, operator, requestUrl, requestMethod);
@ -158,12 +161,14 @@ public class TestPlanService extends TestPlanBaseUtilsService {
private void deleteByList(List<String> testPlanIds) { private void deleteByList(List<String> testPlanIds) {
if (CollectionUtils.isNotEmpty(testPlanIds)) { if (CollectionUtils.isNotEmpty(testPlanIds)) {
TestPlanReportService testPlanReportService = CommonBeanFactory.getBean(TestPlanReportService.class);
BatchProcessUtils.consumerByString(testPlanIds, (deleteIds) -> { BatchProcessUtils.consumerByString(testPlanIds, (deleteIds) -> {
TestPlanExample testPlanExample = new TestPlanExample(); TestPlanExample testPlanExample = new TestPlanExample();
testPlanExample.createCriteria().andIdIn(deleteIds); testPlanExample.createCriteria().andIdIn(deleteIds);
testPlanMapper.deleteByExample(testPlanExample); testPlanMapper.deleteByExample(testPlanExample);
//级联删除 //级联删除
this.cascadeDeleteTestPlanIds(deleteIds); this.cascadeDeleteTestPlanIds(deleteIds, testPlanReportService);
}); });
} }
} }
@ -175,6 +180,7 @@ public class TestPlanService extends TestPlanBaseUtilsService {
*/ */
private void deleteGroupByList(List<String> testPlanGroupIds) { private void deleteGroupByList(List<String> testPlanGroupIds) {
if (CollectionUtils.isNotEmpty(testPlanGroupIds)) { if (CollectionUtils.isNotEmpty(testPlanGroupIds)) {
TestPlanReportService testPlanReportService = CommonBeanFactory.getBean(TestPlanReportService.class);
BatchProcessUtils.consumerByString(testPlanGroupIds, (deleteGroupIds) -> { BatchProcessUtils.consumerByString(testPlanGroupIds, (deleteGroupIds) -> {
/* /*
* 计划组删除逻辑{第一版需求: 删除组, 组下的子计划Group置为None}: * 计划组删除逻辑{第一版需求: 删除组, 组下的子计划Group置为None}:
@ -187,7 +193,7 @@ public class TestPlanService extends TestPlanBaseUtilsService {
List<String> deleteGroupPlanIds = deleteGroupPlans.stream().map(TestPlan::getId).toList(); List<String> deleteGroupPlanIds = deleteGroupPlans.stream().map(TestPlan::getId).toList();
if (CollectionUtils.isNotEmpty(deleteGroupPlanIds)) { if (CollectionUtils.isNotEmpty(deleteGroupPlanIds)) {
// 级联删除子计划关联的资源(计划组不存在关联的资源) // 级联删除子计划关联的资源(计划组不存在关联的资源)
this.cascadeDeleteTestPlanIds(deleteGroupPlanIds); this.cascadeDeleteTestPlanIds(deleteGroupPlanIds, testPlanReportService);
} }
testPlanExample.clear(); testPlanExample.clear();
testPlanExample.createCriteria().andIdIn(ListUtils.union(deleteGroupIds, deleteGroupPlanIds)); testPlanExample.createCriteria().andIdIn(ListUtils.union(deleteGroupIds, deleteGroupPlanIds));
@ -234,8 +240,9 @@ public class TestPlanService extends TestPlanBaseUtilsService {
* 级联删除计划关联的资源 * 级联删除计划关联的资源
* *
* @param testPlanIds 计划ID集合 * @param testPlanIds 计划ID集合
* @param testPlanReportService 这个方法会在批处理中使用所以service在调用处通过传参的方式传入
*/ */
private void cascadeDeleteTestPlanIds(List<String> testPlanIds) { private void cascadeDeleteTestPlanIds(List<String> testPlanIds, TestPlanReportService testPlanReportService) {
//删除当前计划对应的资源 //删除当前计划对应的资源
Map<String, TestPlanResourceService> subTypes = CommonBeanFactory.getBeansOfType(TestPlanResourceService.class); Map<String, TestPlanResourceService> subTypes = CommonBeanFactory.getBeansOfType(TestPlanResourceService.class);
subTypes.forEach((k, t) -> { subTypes.forEach((k, t) -> {
@ -253,11 +260,13 @@ public class TestPlanService extends TestPlanBaseUtilsService {
TestPlanAllocationExample allocationExample = new TestPlanAllocationExample(); TestPlanAllocationExample allocationExample = new TestPlanAllocationExample();
allocationExample.createCriteria().andTestPlanIdIn(testPlanIds); allocationExample.createCriteria().andTestPlanIdIn(testPlanIds);
testPlanAllocationMapper.deleteByExample(allocationExample); testPlanAllocationMapper.deleteByExample(allocationExample);
//删除测试计划报告 todo: 正式版增加接口用例报告接口场景报告的清理
testPlanReportService.deleteByTestPlanIds(testPlanIds);
/* /*
todo todo
删除计划定时任务 删除计划定时任务
*/ */
} }
@ -620,4 +629,19 @@ public class TestPlanService extends TestPlanBaseUtilsService {
throw new MSException(Translator.getWithArgs("tags_length_large_than", String.valueOf(MAX_TAG_SIZE))); throw new MSException(Translator.getWithArgs("tags_length_large_than", String.valueOf(MAX_TAG_SIZE)));
} }
} }
//通过项目删除测试计划
public void deleteByProjectId(String projectId) {
List<String> 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);
});
}
} }

View File

@ -1,16 +1,26 @@
package io.metersphere.plan.controller; 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.TestPlanShareInfo;
import io.metersphere.plan.dto.request.*; import io.metersphere.plan.dto.request.*;
import io.metersphere.plan.dto.response.TestPlanReportPageResponse; 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.constants.ShareInfoType;
import io.metersphere.sdk.util.CommonBeanFactory;
import io.metersphere.sdk.util.JSON; import io.metersphere.sdk.util.JSON;
import io.metersphere.system.base.BaseTest; import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.handler.ResultHolder; import io.metersphere.system.controller.handler.ResultHolder;
import io.metersphere.system.utils.Pager; import io.metersphere.system.utils.Pager;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.*; 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.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.jdbc.Sql; 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 org.springframework.test.web.servlet.MvcResult;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; 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 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_INFO = "/test-plan/report/share/get";
private static final String GET_SHARE_TIME = "/test-plan/report/share/get-share-time"; 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; private static String GEN_REPORT_ID;
@ -227,4 +242,41 @@ public class TestPlanReportControllerTests extends BaseTest {
request.setSort(Map.of("num", "asc")); request.setSort(Map.of("num", "asc"));
this.requestPostWithOk(GET_PLAN_REPORT_DETAIL_FUNCTIONAL_PAGE, request); 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<TestPlanReport> reports = testPlanReportMapper.selectByExample(reportExample);
List<String> 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);
}
} }

View File

@ -4,22 +4,19 @@ import io.metersphere.api.domain.ApiScenario;
import io.metersphere.api.domain.ApiTestCase; 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.TestPlan; import io.metersphere.plan.domain.*;
import io.metersphere.plan.domain.TestPlanConfig;
import io.metersphere.plan.domain.TestPlanExample;
import io.metersphere.plan.domain.TestPlanFunctionalCase;
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.mapper.ExtTestPlanMapper;
import io.metersphere.plan.mapper.TestPlanMapper; import io.metersphere.plan.mapper.TestPlanMapper;
import io.metersphere.plan.service.TestPlanManagementService; import io.metersphere.plan.mapper.TestPlanReportMapper;
import io.metersphere.plan.service.TestPlanModuleService; import io.metersphere.plan.service.*;
import io.metersphere.plan.service.TestPlanService;
import io.metersphere.plan.service.TestPlanTestService;
import io.metersphere.plan.utils.TestPlanTestUtils; import io.metersphere.plan.utils.TestPlanTestUtils;
import io.metersphere.project.domain.Project; import io.metersphere.project.domain.Project;
import io.metersphere.project.dto.filemanagement.request.FileModuleCreateRequest; import io.metersphere.project.dto.filemanagement.request.FileModuleCreateRequest;
import io.metersphere.project.dto.filemanagement.request.FileModuleUpdateRequest; import io.metersphere.project.dto.filemanagement.request.FileModuleUpdateRequest;
import io.metersphere.sdk.constants.*; import io.metersphere.sdk.constants.*;
import io.metersphere.sdk.util.CommonBeanFactory;
import io.metersphere.sdk.util.JSON; import io.metersphere.sdk.util.JSON;
import io.metersphere.system.base.BaseTest; import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.handler.ResultHolder; 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.domain.TestPlanModuleExample;
import io.metersphere.system.dto.AddProjectRequest; import io.metersphere.system.dto.AddProjectRequest;
import io.metersphere.system.dto.sdk.BaseTreeNode; 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.dto.sdk.request.NodeMoveRequest;
import io.metersphere.system.log.constants.OperationLogModule; import io.metersphere.system.log.constants.OperationLogModule;
import io.metersphere.system.log.constants.OperationLogType; 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.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils; 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.junit.jupiter.api.*;
import org.mybatis.spring.SqlSessionUtils;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
@ -129,6 +131,8 @@ public class TestPlanTests extends BaseTest {
private static TestPlan repeatCaseTestPlan; private static TestPlan repeatCaseTestPlan;
private static final String[] PROJECT_MODULE = new String[]{"workstation", "testPlan", "bugManagement", "caseManagement", "apiTest", "uiTest", "loadTest"}; private static final String[] PROJECT_MODULE = new String[]{"workstation", "testPlan", "bugManagement", "caseManagement", "apiTest", "uiTest", "loadTest"};
@Resource
private ExtTestPlanMapper extTestPlanMapper;
@BeforeEach @BeforeEach
public void initTestData() { 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); this.requestPostPermissionTest(PermissionConstants.TEST_PLAN_MODULE_READ_UPDATE, URL_POST_MODULE_UPDATE, updateRequest);
} }
@Resource
private SqlSessionFactory sqlSessionFactory;
@Test @Test
@Order(11) @Order(11)
@ -555,13 +561,41 @@ public class TestPlanTests extends BaseTest {
MvcResult mvcResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_ADD, request); MvcResult mvcResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_ADD, request);
String returnStr = mvcResult.getResponse().getContentAsString(); String returnStr = mvcResult.getResponse().getContentAsString();
ResultHolder holder = JSON.parseObject(returnStr, ResultHolder.class); 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); Assertions.assertNotNull(returnId);
if (i == 7) { if (i == 7) {
groupTestPlanId7 = returnId; groupTestPlanId7 = returnId;
} else if (i == 15) { } else if (i == 15) {
groupTestPlanId15 = returnId; 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); MvcResult mvcResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_ADD, itemRequest);
String returnStr = mvcResult.getResponse().getContentAsString(); String returnStr = mvcResult.getResponse().getContentAsString();
ResultHolder holder = JSON.parseObject(returnStr, ResultHolder.class); 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.setGroupId(groupTestPlanId15);
itemRequest.setName("testPlan_group15_" + i); itemRequest.setName("testPlan_group15_" + i);
mvcResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_ADD, itemRequest); mvcResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_ADD, itemRequest);
returnStr = mvcResult.getResponse().getContentAsString(); returnStr = mvcResult.getResponse().getContentAsString();
holder = JSON.parseObject(returnStr, ResultHolder.class); 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个移动到第一位之前 //将第30个移动到第一位之前
ResourceSortRequest request = new ResourceSortRequest(); ResourceSortRequest request = new ResourceSortRequest();
request.setTestPlanId(repeatCaseTestPlan.getId()); request.setTestPlanId(repeatCaseTestPlan.getId());
request.setDragNodeId(funcList.get(29).getId()); request.setProjectId(DEFAULT_PROJECT_ID);
request.setDropNodeId(funcList.get(0).getId()); request.setMoveId(funcList.get(29).getId());
request.setDropPosition(-1); request.setTargetId(funcList.get(0).getId());
request.setMoveMode(MoveTypeEnum.AFTER.name());
//先测试一下没有开启模块时能否使用 //先测试一下没有开启模块时能否使用
testPlanTestService.removeProjectModule(project, PROJECT_MODULE, "caseManagement"); 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); TestPlanResourceSortResponse response = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), TestPlanResourceSortResponse.class);
Assertions.assertEquals(response.getSortNodeNum(), 1); Assertions.assertEquals(response.getSortNodeNum(), 1);
funcList = testPlanTestService.selectTestPlanFunctionalCaseByTestPlanId(repeatCaseTestPlan.getId()); funcList = testPlanTestService.selectTestPlanFunctionalCaseByTestPlanId(repeatCaseTestPlan.getId());
Assertions.assertEquals(funcList.get(0).getId(), request.getDragNodeId()); Assertions.assertEquals(funcList.get(0).getId(), request.getMoveId());
Assertions.assertEquals(funcList.get(1).getId(), request.getDropNodeId()); Assertions.assertEquals(funcList.get(1).getId(), request.getTargetId());
LOG_CHECK_LIST.add( 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个放到第一位之后 //将这时的第30个放到第一位之后
request.setDragNodeId(funcList.get(29).getId()); request.setMoveId(funcList.get(29).getId());
request.setDropNodeId(funcList.get(0).getId()); request.setTargetId(funcList.get(0).getId());
request.setDropPosition(1); request.setMoveMode(MoveTypeEnum.BEFORE.name());
result = this.requestPostWithOkAndReturn(URL_POST_RESOURCE_FUNCTIONAL_CASE_SORT, request); result = this.requestPostWithOkAndReturn(URL_POST_RESOURCE_FUNCTIONAL_CASE_SORT, request);
resultHolder = JSON.parseObject(result.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class); resultHolder = JSON.parseObject(result.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class);
response = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), TestPlanResourceSortResponse.class); response = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), TestPlanResourceSortResponse.class);
Assertions.assertEquals(response.getSortNodeNum(), 1); Assertions.assertEquals(response.getSortNodeNum(), 1);
funcList = testPlanTestService.selectTestPlanFunctionalCaseByTestPlanId(repeatCaseTestPlan.getId()); funcList = testPlanTestService.selectTestPlanFunctionalCaseByTestPlanId(repeatCaseTestPlan.getId());
Assertions.assertEquals(funcList.get(0).getId(), request.getDropNodeId()); Assertions.assertEquals(funcList.get(0).getId(), request.getTargetId());
Assertions.assertEquals(funcList.get(1).getId(), request.getDragNodeId()); Assertions.assertEquals(funcList.get(1).getId(), request.getMoveId());
LOG_CHECK_LIST.add( 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操作 //再将这时的第30个放到第一位之后,但是第一个的pos为2检查能否触发ref操作
request.setDragNodeId(funcList.get(29).getId()); request.setMoveId(funcList.get(29).getId());
request.setDropNodeId(funcList.get(0).getId()); request.setTargetId(funcList.get(0).getId());
request.setDropPosition(-1); request.setMoveMode(MoveTypeEnum.AFTER.name());
testPlanTestService.setResourcePos(funcList.get(0).getId(), TestPlanResourceConstants.RESOURCE_FUNCTIONAL_CASE, 2); testPlanTestService.setResourcePos(funcList.get(0).getId(), TestPlanResourceConstants.RESOURCE_FUNCTIONAL_CASE, 2);
result = this.requestPostWithOkAndReturn(URL_POST_RESOURCE_FUNCTIONAL_CASE_SORT, request); result = this.requestPostWithOkAndReturn(URL_POST_RESOURCE_FUNCTIONAL_CASE_SORT, request);
resultHolder = JSON.parseObject(result.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class); resultHolder = JSON.parseObject(result.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class);
response = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), TestPlanResourceSortResponse.class); response = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), TestPlanResourceSortResponse.class);
Assertions.assertEquals(response.getSortNodeNum(), 1); Assertions.assertEquals(response.getSortNodeNum(), 1);
funcList = testPlanTestService.selectTestPlanFunctionalCaseByTestPlanId(repeatCaseTestPlan.getId()); funcList = testPlanTestService.selectTestPlanFunctionalCaseByTestPlanId(repeatCaseTestPlan.getId());
Assertions.assertEquals(funcList.get(0).getId(), request.getDragNodeId()); Assertions.assertEquals(funcList.get(0).getId(), request.getMoveId());
Assertions.assertEquals(funcList.get(1).getId(), request.getDropNodeId()); Assertions.assertEquals(funcList.get(1).getId(), request.getTargetId());
LOG_CHECK_LIST.add( 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()); this.requestPost(URL_POST_RESOURCE_FUNCTIONAL_CASE_SORT, request).andExpect(status().is5xxServerError());
//反例拖拽的节点不存在 //反例拖拽的节点不存在
request.setTestPlanId(repeatCaseTestPlan.getId()); request.setTestPlanId(repeatCaseTestPlan.getId());
request.setDragNodeId(null); request.setMoveId(null);
this.requestPost(URL_POST_RESOURCE_FUNCTIONAL_CASE_SORT, request).andExpect(status().is5xxServerError()); this.requestPost(URL_POST_RESOURCE_FUNCTIONAL_CASE_SORT, request).andExpect(status().isBadRequest());
//反例目标节点不存在 //反例目标节点不存在
request.setDragNodeId(funcList.get(29).getId()); request.setMoveId(funcList.get(29).getId());
request.setDropNodeId(null); request.setTargetId(null);
this.requestPost(URL_POST_RESOURCE_FUNCTIONAL_CASE_SORT, request).andExpect(status().is5xxServerError()); this.requestPost(URL_POST_RESOURCE_FUNCTIONAL_CASE_SORT, request).andExpect(status().isBadRequest());
//反例 节点重复 //反例 节点重复
request.setDropNodeId(request.getDragNodeId()); request.setTargetId(request.getMoveId());
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);
this.requestPost(URL_POST_RESOURCE_FUNCTIONAL_CASE_SORT, request).andExpect(status().is5xxServerError()); 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); this.requestPostPermissionTest(PermissionConstants.TEST_PLAN_READ_UPDATE, URL_POST_RESOURCE_FUNCTIONAL_CASE_SORT, request);
} }
@ -1362,10 +1393,10 @@ public class TestPlanTests extends BaseTest {
@Test @Test
@Order(101) @Order(101)
public void deleteTestPlanTest() throws Exception { public void deleteTestPlanTest() throws Exception {
int allDataInDB = 999 + 40;
if (StringUtils.isEmpty(groupTestPlanId7)) { if (StringUtils.isEmpty(groupTestPlanId7)) {
this.testPlanAddTest(); this.testPlanAddTest();
} }
int allDataInDB = 999 + 40;
//根据id删除 删除 第61这1个) //根据id删除 删除 第61这1个)
List<TestPlan> testPlanList = testPlanTestService.selectByProjectIdAndNames(project.getId(), List<TestPlan> testPlanList = testPlanTestService.selectByProjectIdAndNames(project.getId(),
@ -1445,12 +1476,17 @@ public class TestPlanTests extends BaseTest {
request.setType("ALL"); request.setType("ALL");
this.requestPostWithOk(URL_POST_TEST_PLAN_BATCH_DELETE, request); this.requestPostWithOk(URL_POST_TEST_PLAN_BATCH_DELETE, request);
testPlanTestService.checkDataCount(project.getId(), allDataInDB); testPlanTestService.checkDataCount(project.getId(), allDataInDB);
TestPlanExample deleteExample = new TestPlanExample();
deleteExample.createCriteria().andProjectIdEqualTo(project.getId());
} }
@Test @Test
@Order(102) @Order(102)
public void deleteModuleTest() throws Exception { public void deleteModuleTest() throws Exception {
this.preliminaryTree(); this.preliminaryTree();
List<String> testPlanIdList = extTestPlanMapper.selectIdByProjectId(project.getId());
// 删除没有文件的节点a1-b1-c1 检查是否级联删除根节点 // 删除没有文件的节点a1-b1-c1 检查是否级联删除根节点
BaseTreeNode a1b1Node = TestPlanTestUtils.getNodeByName(this.getFileModuleTreeNode(), "a1-b1"); 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, IDGenerator.nextNum())).andExpect(status().is5xxServerError());
// 测试删除根节点(根节点无法删除 // 测试删除根节点(根节点无法删除
this.requestGet(String.format(URL_GET_MODULE_DELETE, ModuleConstants.DEFAULT_NODE_ID)).andExpect(status().is5xxServerError()); this.requestGet(String.format(URL_GET_MODULE_DELETE, ModuleConstants.DEFAULT_NODE_ID)).andExpect(status().is5xxServerError());
;
//service层判断测试删除空集合 //service层判断测试删除空集合
testPlanModuleService.deleteModule(new ArrayList<>(), project.getId(), null, null, null); 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()))); 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) { private void checkModuleIsEmpty(String id) {
TestPlanModuleExample example = new TestPlanModuleExample(); TestPlanModuleExample example = new TestPlanModuleExample();
example.createCriteria().andParentIdEqualTo(id); example.createCriteria().andParentIdEqualTo(id);
@ -1687,7 +1743,7 @@ public class TestPlanTests extends BaseTest {
MvcResult mvcResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_ADD, request); MvcResult mvcResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_ADD, request);
String returnStr = mvcResult.getResponse().getContentAsString(); String returnStr = mvcResult.getResponse().getContentAsString();
ResultHolder holder = JSON.parseObject(returnStr, ResultHolder.class); 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); Assertions.assertNotNull(returnId);
TestPlanUpdateRequest updateRequest = new TestPlanUpdateRequest(); TestPlanUpdateRequest updateRequest = new TestPlanUpdateRequest();

View File

@ -15,6 +15,8 @@ import io.metersphere.project.domain.Project;
import io.metersphere.project.mapper.ProjectMapper; import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.sdk.constants.*; import io.metersphere.sdk.constants.*;
import io.metersphere.sdk.util.JSON; 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.IDGenerator;
import io.metersphere.system.uid.NumGenerator; import io.metersphere.system.uid.NumGenerator;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
@ -37,6 +39,12 @@ public class TestPlanTestService {
@Resource @Resource
private FunctionalCaseMapper functionalCaseMapper; private FunctionalCaseMapper functionalCaseMapper;
@Resource @Resource
private TestPlanFollowerMapper testPlanFollowerMapper;
@Resource
private TestPlanAllocationMapper testPlanAllocationMapper;
@Resource
private TestPlanReportMapper testPlanReportMapper;
@Resource
private TestPlanFunctionalCaseMapper testPlanFunctionalCaseMapper; private TestPlanFunctionalCaseMapper testPlanFunctionalCaseMapper;
@Resource @Resource
private TestPlanApiCaseMapper testPlanApiCaseMapper; private TestPlanApiCaseMapper testPlanApiCaseMapper;
@ -379,4 +387,46 @@ public class TestPlanTestService {
testPlanApiScenarioMapper.updateByPrimaryKeySelective(updateCase); testPlanApiScenarioMapper.updateByPrimaryKeySelective(updateCase);
} }
} }
public void checkDataEmpty(List<String> 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);
});
}
} }