diff --git a/backend/app/src/main/resources/banner.txt b/backend/app/src/main/resources/banner.txt new file mode 100644 index 0000000000..6dd476e045 --- /dev/null +++ b/backend/app/src/main/resources/banner.txt @@ -0,0 +1,7 @@ + +███╗ ███╗███████╗████████╗███████╗██████╗ ███████╗██████╗ ██╗ ██╗███████╗██████╗ ███████╗ +████╗ ████║██╔════╝╚══██╔══╝██╔════╝██╔══██╗██╔════╝██╔══██╗██║ ██║██╔════╝██╔══██╗██╔════╝ +██╔████╔██║█████╗ ██║ █████╗ ██████╔╝███████╗██████╔╝███████║█████╗ ██████╔╝█████╗ +██║╚██╔╝██║██╔══╝ ██║ ██╔══╝ ██╔══██╗╚════██║██╔═══╝ ██╔══██║██╔══╝ ██╔══██╗██╔══╝ +██║ ╚═╝ ██║███████╗ ██║ ███████╗██║ ██║███████║██║ ██║ ██║███████╗██║ ██║███████╗ +╚═╝ ╚═╝╚══════╝ ╚═╝ ╚══════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚══════╝ diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/log/constants/OperationLogModule.java b/backend/services/system-setting/src/main/java/io/metersphere/system/log/constants/OperationLogModule.java index a61071b2cc..6b1f15c39d 100644 --- a/backend/services/system-setting/src/main/java/io/metersphere/system/log/constants/OperationLogModule.java +++ b/backend/services/system-setting/src/main/java/io/metersphere/system/log/constants/OperationLogModule.java @@ -154,6 +154,7 @@ public class OperationLogModule { public static final String BUG_MANAGEMENT_RECYCLE = "BUG_MANAGEMENT_BUG_RECYCLE"; //测试计划 public static final String TEST_PLAN = "TEST_PLAN"; + public static final String TEST_PLAN_INDEX = "TEST_PLAN_INDEX"; public static final String TEST_PLAN_MODULE = "TEST_PLAN_MODULE"; public static final String TEST_PLAN_REPORT = "TEST_PLAN_REPORT"; 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 9371470539..8c2a9a05b7 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 @@ -201,7 +201,7 @@ public class TestPlanController { @Operation(summary = "测试计划-批量归档") @RequiresPermissions(PermissionConstants.TEST_PLAN_READ_UPDATE) @CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project") - public void batchArchived(@Validated @RequestBody TestPlanBatchRequest request) { + public void batchArchived(@Validated @RequestBody TestPlanBatchProcessRequest request) { testPlanManagementService.checkModuleIsOpen(request.getProjectId(), TestPlanResourceConfig.CHECK_TYPE_PROJECT, Collections.singletonList(TestPlanResourceConfig.CONFIG_TEST_PLAN)); testPlanService.batchArchived(request, SessionUtils.getUserId()); } diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanBatchArchivedService.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanBatchArchivedService.java deleted file mode 100644 index c86d565a00..0000000000 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanBatchArchivedService.java +++ /dev/null @@ -1,71 +0,0 @@ -package io.metersphere.plan.service; - -import io.metersphere.plan.domain.TestPlan; -import io.metersphere.plan.domain.TestPlanExample; -import io.metersphere.plan.dto.request.TestPlanBatchProcessRequest; -import io.metersphere.plan.dto.request.TestPlanBatchRequest; -import io.metersphere.plan.mapper.TestPlanMapper; -import io.metersphere.sdk.constants.TestPlanConstants; -import io.metersphere.sdk.exception.MSException; -import io.metersphere.sdk.util.Translator; -import jakarta.annotation.Resource; -import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.StringUtils; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -@Service -@Transactional(rollbackFor = Exception.class) -public class TestPlanBatchArchivedService extends TestPlanBaseUtilsService { - - @Resource - private TestPlanMapper testPlanMapper; - - public void batchArchived(Map> plans, TestPlanBatchRequest request, String userId) { - int affectedGroupPlanCount = batchArchivedGroup(plans, request, userId); - int affectedPlanCount = batchArchivedPlan(plans, userId); - if (affectedGroupPlanCount <= 0 && affectedPlanCount <= 0) { - // 暂无可归档的计划 - throw new MSException(Translator.get("no_plan_to_archive")); - } - } - - /** - * 批量归档组 - * - * @param planGroups 计划组 - */ - private int batchArchivedGroup(Map> planGroups, TestPlanBatchProcessRequest request, String userId) { - //TODO 批量归档计划组 - return 0; - } - - /** - * 批量归档计划 - * - * @param plans 归档测试计划集合 - */ - private int batchArchivedPlan(Map> plans, String userId) { - if (plans.containsKey(TestPlanConstants.TEST_PLAN_TYPE_PLAN)) { - List testPlans = plans.get(TestPlanConstants.TEST_PLAN_TYPE_PLAN); - List ids = testPlans.stream().filter(plan -> StringUtils.equals(plan.getStatus(), TestPlanConstants.TEST_PLAN_STATUS_COMPLETED)) - .map(TestPlan::getId).collect(Collectors.toList()); - if (CollectionUtils.isEmpty(ids)) { - return 0; - } - TestPlan record = new TestPlan(); - record.setStatus(TestPlanConstants.TEST_PLAN_STATUS_ARCHIVED); - record.setUpdateUser(userId); - record.setUpdateTime(System.currentTimeMillis()); - TestPlanExample example = new TestPlanExample(); - example.createCriteria().andIdIn(ids); - return testPlanMapper.updateByExampleSelective(record, example); - } else { - return 0; - } - } -} diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanBatchOperationService.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanBatchOperationService.java index 34a520c050..0bd2b96f9f 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanBatchOperationService.java +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanBatchOperationService.java @@ -1,10 +1,9 @@ package io.metersphere.plan.service; -import io.metersphere.plan.domain.TestPlan; -import io.metersphere.plan.domain.TestPlanConfig; -import io.metersphere.plan.domain.TestPlanExample; +import io.metersphere.plan.domain.*; import io.metersphere.plan.dto.response.TestPlanResponse; import io.metersphere.plan.mapper.ExtTestPlanMapper; +import io.metersphere.plan.mapper.TestPlanCollectionMapper; import io.metersphere.plan.mapper.TestPlanConfigMapper; import io.metersphere.plan.mapper.TestPlanMapper; import io.metersphere.project.utils.NodeSortUtils; @@ -12,6 +11,7 @@ import io.metersphere.sdk.constants.ApplicationNumScope; 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.Translator; import io.metersphere.system.uid.IDGenerator; import io.metersphere.system.uid.NumGenerator; @@ -23,10 +23,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; +import java.util.*; @Service @Transactional(rollbackFor = Exception.class) @@ -43,6 +40,8 @@ public class TestPlanBatchOperationService extends TestPlanBaseUtilsService { private TestPlanConfigMapper testPlanConfigMapper; @Autowired private ApplicationContext applicationContext; + @Resource + private TestPlanCollectionMapper testPlanCollectionMapper; public long batchMoveModule(List testPlanList, String moduleId, String userId) { List movePlanIds = new ArrayList<>(); @@ -124,10 +123,11 @@ public class TestPlanBatchOperationService extends TestPlanBaseUtilsService { */ for (TestPlan copyPlan : copyPlanList) { if (StringUtils.equalsIgnoreCase(copyPlan.getType(), TestPlanConstants.TEST_PLAN_TYPE_GROUP)) { - copyCount += this.copyPlanGroup(copyPlan, targetId, targetType, operatorTime, userId); + this.copyPlanGroup(copyPlan, targetId, targetType, operatorTime, userId); } else { - copyCount += this.copyPlan(copyPlan, targetId, targetType, operatorTime, userId); + this.copyPlan(copyPlan, targetId, targetType, operatorTime, userId); } + copyCount++; } return copyCount; } @@ -143,10 +143,10 @@ public class TestPlanBatchOperationService extends TestPlanBaseUtilsService { * @param operator 操作人 * @return 复制的数量 */ - public int copyPlan(TestPlan originalTestPlan, String targetId, String targetType, long operatorTime, String operator) { + public TestPlan copyPlan(TestPlan originalTestPlan, String targetId, String targetType, long operatorTime, String operator) { //已归档的无法操作 if (StringUtils.equalsIgnoreCase(originalTestPlan.getStatus(), TestPlanConstants.TEST_PLAN_STATUS_ARCHIVED)) { - return 0; + throw new MSException(Translator.get("test_plan.error")); } String moduleId = originalTestPlan.getModuleId(); String groupId = originalTestPlan.getGroupId(); @@ -194,33 +194,65 @@ public class TestPlanBatchOperationService extends TestPlanBaseUtilsService { testPlanConfigMapper.insertSelective(newTestPlanConfig); } - //todo 测试规划信息 + //测试规划信息 + TestPlanCollectionExample parentCollectionExample = new TestPlanCollectionExample(); + parentCollectionExample.createCriteria().andTestPlanIdEqualTo(originalTestPlan.getId()).andParentIdEqualTo(TestPlanConstants.DEFAULT_PARENT_ID); + List testPlanCollectionList = testPlanCollectionMapper.selectByExample(parentCollectionExample); + if (CollectionUtils.isEmpty(testPlanCollectionList)) { + //自动生成测试规划 + Objects.requireNonNull(CommonBeanFactory.getBean(TestPlanService.class)).initDefaultPlanCollection(testPlan.getId(), operator); + } else { + List newTestPlanCollectionList = new ArrayList<>(); + for (TestPlanCollection testPlanCollection : testPlanCollectionList) { + TestPlanCollection newTestPlanCollection = new TestPlanCollection(); + BeanUtils.copyBean(newTestPlanCollection, testPlanCollection); + newTestPlanCollection.setId(IDGenerator.nextStr()); + newTestPlanCollection.setTestPlanId(testPlan.getId()); + newTestPlanCollection.setCreateUser(operator); + newTestPlanCollection.setCreateTime(operatorTime); + newTestPlanCollectionList.add(newTestPlanCollection); + + //查找测试集信息 + TestPlanCollectionExample childExample = new TestPlanCollectionExample(); + childExample.createCriteria().andParentIdEqualTo(testPlanCollection.getId()); + List children = testPlanCollectionMapper.selectByExample(childExample); + for (TestPlanCollection child : children) { + TestPlanCollection childCollection = new TestPlanCollection(); + BeanUtils.copyBean(childCollection, child); + childCollection.setId(IDGenerator.nextStr()); + childCollection.setParentId(newTestPlanCollection.getId()); + childCollection.setTestPlanId(testPlan.getId()); + childCollection.setCreateUser(operator); + childCollection.setCreateTime(operatorTime); + newTestPlanCollectionList.add(childCollection); + } + } + testPlanCollectionMapper.batchInsert(newTestPlanCollectionList); + } //测试用例信息 Map beansOfType = applicationContext.getBeansOfType(TestPlanResourceService.class); beansOfType.forEach((k, v) -> { v.copyResource(originalTestPlan.getId(), testPlan.getId(), operator, operatorTime); }); - return 1; + return testPlan; } - public int copyPlanGroup(TestPlan originalGroup, String targetId, String targetType, long operatorTime, String operator) { + public TestPlan copyPlanGroup(TestPlan originalGroup, String targetId, String targetType, long operatorTime, String operator) { //测试计划组复制的时候,只支持targetType为module的操作. 已归档的无法操作 if (StringUtils.equalsIgnoreCase(targetType, TestPlanConstants.TEST_PLAN_TYPE_GROUP) || StringUtils.equalsIgnoreCase(originalGroup.getStatus(), TestPlanConstants.TEST_PLAN_STATUS_ARCHIVED)) { - return 0; + throw new MSException(Translator.get("test_plan.group.error")); } super.checkModule(targetId); String moduleId = targetId; TestPlanExample example = new TestPlanExample(); - example.createCriteria().andGroupIdEqualTo(originalGroup.getId()); + example.createCriteria().andGroupIdEqualTo(originalGroup.getId()).andStatusNotEqualTo(TestPlanConstants.TEST_PLAN_STATUS_ARCHIVED); example.setOrderByClause("pos asc"); List childList = testPlanMapper.selectByExample(example); - int copyCount = 0; - TestPlan testPlanGroup = new TestPlan(); BeanUtils.copyBean(testPlanGroup, originalGroup); testPlanGroup.setId(IDGenerator.nextStr()); @@ -232,13 +264,12 @@ public class TestPlanBatchOperationService extends TestPlanBaseUtilsService { testPlanGroup.setUpdateTime(operatorTime); testPlanGroup.setModuleId(moduleId); testPlanGroup.setStatus(TestPlanConstants.TEST_PLAN_STATUS_PREPARED); - copyCount += testPlanMapper.insert(testPlanGroup); + testPlanMapper.insert(testPlanGroup); for (TestPlan child : childList) { - copyCount += copyPlan(child, testPlanGroup.getId(), TestPlanConstants.TEST_PLAN_TYPE_GROUP, operatorTime, operator); + copyPlan(child, testPlanGroup.getId(), TestPlanConstants.TEST_PLAN_TYPE_GROUP, operatorTime, operator); } - - return copyCount; + return testPlanGroup; } private String getCopyName(String name, long oldNum, long newNum) { diff --git a/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanLogService.java b/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanLogService.java index c1e4f25456..7da5e7ae3d 100644 --- a/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanLogService.java +++ b/backend/services/test-plan/src/main/java/io/metersphere/plan/service/TestPlanLogService.java @@ -3,12 +3,10 @@ package io.metersphere.plan.service; import io.metersphere.plan.domain.TestPlan; import io.metersphere.plan.domain.TestPlanExample; import io.metersphere.plan.dto.request.TestPlanBatchEditRequest; -import io.metersphere.plan.dto.request.TestPlanCopyRequest; import io.metersphere.plan.mapper.TestPlanMapper; import io.metersphere.project.domain.Project; import io.metersphere.project.mapper.ProjectMapper; import io.metersphere.sdk.constants.HttpMethodConstants; -import io.metersphere.sdk.constants.TestPlanConstants; import io.metersphere.sdk.util.JSON; import io.metersphere.sdk.util.Translator; import io.metersphere.system.dto.LogInsertModule; @@ -32,7 +30,7 @@ import java.util.stream.Collectors; @Transactional(rollbackFor = Exception.class) public class TestPlanLogService { - private String logModule = OperationLogModule.TEST_PLAN; + private String logModule = OperationLogModule.TEST_PLAN_INDEX; @Resource private ProjectMapper projectMapper; @@ -48,7 +46,7 @@ public class TestPlanLogService { .projectId(project.getId()) .organizationId(project.getOrganizationId()) .type(OperationLogType.UPDATE.name()) - .module(OperationLogModule.TEST_PLAN) + .module(logModule) .sourceId(testPlan.getId()) .content(Translator.get("test_plan_schedule") + ":" + testPlan.getName()) .build().getLogDTO(); @@ -100,7 +98,7 @@ public class TestPlanLogService { .method(requestMethod) .path(requestUrl) .sourceId(newTestPlan.getId()) - .content(generateTestPlanSimpleContent(newTestPlan, Translator.get("update"))) + .content(newTestPlan.getName()) .originalValue(JSON.toJSONBytes(oldTestPlan)) .modifiedValue(JSON.toJSONBytes(newTestPlan)) .createUser(operator) @@ -126,7 +124,7 @@ public class TestPlanLogService { .method(requestMethod) .path(requestUrl) .sourceId(deleteTestPlan.getId()) - .content(generateTestPlanSimpleContent(deleteTestPlan, Translator.get("delete"))) + .content(deleteTestPlan.getName()) .originalValue(JSON.toJSONBytes(deleteTestPlan)) .createUser(operator) .build().getLogDTO(); @@ -157,25 +155,23 @@ public class TestPlanLogService { /** * 复制日志 - * - * @param request 请求参数 - * @return 日志对象 */ - public LogDTO copyLog(TestPlanCopyRequest request) { - TestPlan testPlan = testPlanMapper.selectByPrimaryKey(request.getId()); - testPlan.setName(request.getName()); - LogDTO dto = new LogDTO( - request.getProjectId(), - null, - null, - null, - OperationLogType.COPY.name(), - logModule, - generateTestPlanSimpleContent(testPlan, Translator.get("copy"))); - dto.setPath("/test-plan/copy"); - dto.setMethod(HttpMethodConstants.POST.name()); - dto.setOriginalValue(JSON.toJSONBytes(request)); - return dto; + public void copyLog(TestPlan testPlan, String operator) { + if (testPlan != null) { + Project project = projectMapper.selectByPrimaryKey(testPlan.getProjectId()); + LogDTO dto = new LogDTO( + testPlan.getProjectId(), + project.getOrganizationId(), + testPlan.getId(), + operator, + OperationLogType.COPY.name(), + logModule, + testPlan.getName()); + dto.setPath("/test-plan/copy"); + dto.setMethod(HttpMethodConstants.POST.name()); + dto.setOriginalValue(JSON.toJSONBytes(testPlan)); + operationLogService.add(dto); + } } /** @@ -200,7 +196,7 @@ public class TestPlanLogService { .method(requestMethod) .path(requestUrl) .sourceId(plan.getId()) - .content(generateTestPlanSimpleContent(plan, Translator.get(typeKey))) + .content(plan.getName()) .originalValue(JSON.toJSONBytes(plan)) .createUser(operator) .build().getLogDTO(); @@ -209,24 +205,6 @@ public class TestPlanLogService { operationLogService.batchAdd(list); } - /** - * 生成计划操作日志内容 - * - * @param testPlan 测试计划 - * @param type 类型 - * @return 日志内容 - */ - private String generateTestPlanSimpleContent(TestPlan testPlan, String type) { - StringBuilder content = new StringBuilder(); - if (StringUtils.equals(testPlan.getType(), TestPlanConstants.TEST_PLAN_TYPE_GROUP)) { - content.append(Translator.getWithArgs("test_plan_group.batch.log", type)).append(StringUtils.SPACE).append(testPlan.getName()).append(StringUtils.SPACE); - } else { - content.append(Translator.getWithArgs("test_plan.batch.log", type)).append(StringUtils.SPACE).append(testPlan.getName()).append(StringUtils.SPACE); - } - return content.toString(); - } - - /** * 批量编辑 * @@ -250,7 +228,7 @@ public class TestPlanLogService { testPlan.getId(), null, OperationLogType.UPDATE.name(), - OperationLogModule.TEST_PLAN, + logModule, testPlan.getName()); dto.setPath("/test-plan/batch-edit"); dto.setMethod(HttpMethodConstants.POST.name()); 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 9169c98dd6..04496a77e7 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 @@ -75,8 +75,6 @@ public class TestPlanService extends TestPlanBaseUtilsService { @Resource private TestPlanBatchOperationService testPlanBatchOperationService; @Resource - private TestPlanBatchArchivedService testPlanBatchArchivedService; - @Resource private TestPlanStatisticsService testPlanStatisticsService; @Resource private TestPlanCaseService testPlanCaseService; @@ -113,6 +111,12 @@ public class TestPlanService extends TestPlanBaseUtilsService { TestPlan testPlan = savePlanDTO(testPlanCreateRequest, operator); //自动生成测试规划 this.initDefaultPlanCollection(testPlan.getId(), operator); + + if (!StringUtils.equalsIgnoreCase(testPlan.getGroupId(), TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID)) { + //更新计划组状态 + this.updateTestPlanGroupStatus(testPlan.getGroupId()); + } + testPlanLogService.saveAddLog(testPlan, operator, requestUrl, requestMethod); return testPlan; } @@ -152,9 +156,6 @@ public class TestPlanService extends TestPlanBaseUtilsService { testPlanConfig.setRepeatCase(createOrCopyRequest.isRepeatCase()); testPlanConfig.setPassThreshold(createOrCopyRequest.getPassThreshold()); - //正式版本不再支持这种操作 - // handleAssociateCase(createOrCopyRequest.getBaseAssociateCaseRequest(), operator, createTestPlan); - testPlanMapper.insert(createTestPlan); testPlanConfigMapper.insertSelective(testPlanConfig); return createTestPlan; @@ -202,13 +203,17 @@ public class TestPlanService extends TestPlanBaseUtilsService { public void delete(String id, String operator, String requestUrl, String requestMethod) { TestPlan testPlan = testPlanMapper.selectByPrimaryKey(id); if (StringUtils.equals(testPlan.getType(), TestPlanConstants.TEST_PLAN_TYPE_GROUP)) { - // 计划组的删除暂时预留 this.deleteGroupByList(Collections.singletonList(testPlan.getId())); } else { testPlanMapper.deleteByPrimaryKey(id); //级联删除 TestPlanReportService testPlanReportService = CommonBeanFactory.getBean(TestPlanReportService.class); this.cascadeDeleteTestPlanIds(Collections.singletonList(id), testPlanReportService); + + if (!StringUtils.equalsIgnoreCase(testPlan.getGroupId(), TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID)) { + //更新计划组状态 + this.updateTestPlanGroupStatus(testPlan.getGroupId()); + } } //记录日志 testPlanLogService.saveDeleteLog(testPlan, operator, requestUrl, requestMethod); @@ -357,7 +362,9 @@ public class TestPlanService extends TestPlanBaseUtilsService { updateTestPlan.setPlannedStartTime(request.getPlannedStartTime()); updateTestPlan.setPlannedEndTime(request.getPlannedEndTime()); updateTestPlan.setDescription(request.getDescription()); - updateTestPlan.setGroupId(request.getGroupId()); + if (CollectionUtils.isNotEmpty(request.getTags())) { + updateTestPlan.setTags(new ArrayList<>(request.getTags())); + } updateTestPlan.setType(testPlan.getType()); testPlanMapper.updateByPrimaryKeySelective(updateTestPlan); } @@ -406,12 +413,16 @@ public class TestPlanService extends TestPlanBaseUtilsService { if (StringUtils.equalsAnyIgnoreCase(testPlan.getType(), TestPlanConstants.TEST_PLAN_TYPE_GROUP)) { //测试计划组归档 updateGroupStatus(testPlan.getId(), userId); + //关闭定时任务 + } else if (StringUtils.equals(testPlan.getStatus(), TestPlanConstants.TEST_PLAN_STATUS_COMPLETED) && StringUtils.equalsIgnoreCase(testPlan.getGroupId(), TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID)) { //测试计划 testPlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_ARCHIVED); testPlan.setUpdateUser(userId); testPlan.setUpdateTime(System.currentTimeMillis()); testPlanMapper.updateByPrimaryKeySelective(testPlan); + //关闭定时任务 + this.deleteScheduleConfig(testPlan.getId()); } else { throw new MSException(Translator.get("test_plan.cannot.archived")); } @@ -424,14 +435,16 @@ public class TestPlanService extends TestPlanBaseUtilsService { * @param request 批量请求参数 * @param currentUser 当前用户 */ - public void batchArchived(TestPlanBatchRequest request, String currentUser) { + public void batchArchived(TestPlanBatchProcessRequest request, String currentUser) { List batchArchivedIds = request.getSelectIds(); if (CollectionUtils.isNotEmpty(batchArchivedIds)) { TestPlanExample example = new TestPlanExample(); - example.createCriteria().andIdIn(batchArchivedIds).andStatusEqualTo(TestPlanConstants.TEST_PLAN_STATUS_COMPLETED); - List archivedPlanList = testPlanMapper.selectByExample(example); - Map> plans = archivedPlanList.stream().collect(Collectors.groupingBy(TestPlan::getType)); - testPlanBatchArchivedService.batchArchived(plans, request, currentUser); + example.createCriteria().andIdIn(batchArchivedIds); + List archivedPlanList = testPlanMapper.selectByExample(example).stream().filter( + testPlan -> StringUtils.equalsAnyIgnoreCase(testPlan.getType(), TestPlanConstants.TEST_PLAN_TYPE_GROUP) + || (StringUtils.equals(testPlan.getStatus(), TestPlanConstants.TEST_PLAN_STATUS_COMPLETED) && StringUtils.equalsIgnoreCase(testPlan.getGroupId(), TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID)) + ).collect(Collectors.toList()); + archivedPlanList.forEach(item -> this.archived(item.getId(), currentUser)); //日志 testPlanLogService.saveBatchLog(archivedPlanList, currentUser, "/test-plan/batch-archived", HttpMethodConstants.POST.name(), OperationLogType.UPDATE.name(), "archive"); } @@ -461,13 +474,15 @@ public class TestPlanService extends TestPlanBaseUtilsService { * 复制测试计划 */ public long copy(String testPlanId, String userId) { - TestPlan testPlan = testPlanMapper.selectByPrimaryKey(testPlanId); + TestPlan copyPlan = null; if (StringUtils.equalsIgnoreCase(testPlan.getType(), TestPlanConstants.TEST_PLAN_TYPE_GROUP)) { - return testPlanBatchOperationService.copyPlanGroup(testPlan, testPlan.getModuleId(), ModuleConstants.NODE_TYPE_DEFAULT, System.currentTimeMillis(), userId); + copyPlan = testPlanBatchOperationService.copyPlanGroup(testPlan, testPlan.getModuleId(), ModuleConstants.NODE_TYPE_DEFAULT, System.currentTimeMillis(), userId); } else { - return testPlanBatchOperationService.copyPlan(testPlan, testPlan.getGroupId(), TestPlanConstants.TEST_PLAN_TYPE_GROUP, System.currentTimeMillis(), userId); + copyPlan = testPlanBatchOperationService.copyPlan(testPlan, testPlan.getGroupId(), TestPlanConstants.TEST_PLAN_TYPE_GROUP, System.currentTimeMillis(), userId); } + testPlanLogService.copyLog(copyPlan, userId); + return 1; } /** @@ -784,23 +799,39 @@ public class TestPlanService extends TestPlanBaseUtilsService { testPlan = testPlanMapper.selectByPrimaryKey(testPlanId); if (!StringUtils.equalsIgnoreCase(testPlan.getGroupId(), TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID)) { - //该测试计划是测试计划组内的子计划, 要同步计算测试计划组的状态 - List childPlan = this.selectNotArchivedChildren(testPlan.getGroupId()); - if (CollectionUtils.isNotEmpty(childPlan)) { - TestPlan updateGroupPlan = new TestPlan(); - updateGroupPlan.setId(testPlan.getGroupId()); - if (childPlan.stream().allMatch(item -> StringUtils.equals(item.getStatus(), TestPlanConstants.TEST_PLAN_STATUS_COMPLETED))) { - updateGroupPlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_COMPLETED); - } else { - updateGroupPlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_UNDERWAY); - } - testPlanMapper.updateByPrimaryKeySelective(updateGroupPlan); + this.updateTestPlanGroupStatus(testPlan.getGroupId()); + } + } - if (StringUtils.equalsIgnoreCase(updateGroupPlan.getStatus(), TestPlanConstants.TEST_PLAN_STATUS_COMPLETED)) { - extTestPlanMapper.setActualEndTime(testPlan.getGroupId(), System.currentTimeMillis()); + private void updateTestPlanGroupStatus(String testPlanGroupId) { + //该测试计划是测试计划组内的子计划, 要同步计算测试计划组的状态 + List childPlan = this.selectNotArchivedChildren(testPlanGroupId); + String groupStatus = TestPlanConstants.TEST_PLAN_STATUS_PREPARED; + + // 未开始:计划组为空、组内所有计划都是“未开始”状态 + // 已完成:组内计划均为“已完成”状态 + // 进行中:组内计划有未完成的状态 + if (CollectionUtils.isNotEmpty(childPlan)) { + List testPlanStatus = childPlan.stream().map(TestPlan::getStatus).distinct().toList(); + if (testPlanStatus.size() == 1) { + if (StringUtils.equals(testPlanStatus.getFirst(), TestPlanConstants.TEST_PLAN_STATUS_COMPLETED)) { + groupStatus = TestPlanConstants.TEST_PLAN_STATUS_COMPLETED; + } else if (StringUtils.equals(testPlanStatus.getFirst(), TestPlanConstants.TEST_PLAN_STATUS_PREPARED)) { + groupStatus = TestPlanConstants.TEST_PLAN_STATUS_PREPARED; + } else if (StringUtils.equals(testPlanStatus.getFirst(), TestPlanConstants.TEST_PLAN_STATUS_UNDERWAY)) { + groupStatus = TestPlanConstants.TEST_PLAN_STATUS_UNDERWAY; } + } else { + groupStatus = TestPlanConstants.TEST_PLAN_STATUS_UNDERWAY; } } + TestPlan updateGroupPlan = new TestPlan(); + updateGroupPlan.setId(testPlanGroupId); + updateGroupPlan.setStatus(groupStatus); + testPlanMapper.updateByPrimaryKeySelective(updateGroupPlan); + if (StringUtils.equalsIgnoreCase(updateGroupPlan.getStatus(), TestPlanConstants.TEST_PLAN_STATUS_COMPLETED)) { + extTestPlanMapper.setActualEndTime(testPlanGroupId, System.currentTimeMillis()); + } } public void refreshTestPlanStatus(String testPlanId) { @@ -875,6 +906,12 @@ public class TestPlanService extends TestPlanBaseUtilsService { public void deleteScheduleConfig(String testPlanId) { scheduleService.deleteByResourceId(testPlanId, TestPlanScheduleJob.getJobKey(testPlanId), TestPlanScheduleJob.getTriggerKey(testPlanId)); + + //判断有没有测试计划组 + TestPlanExample testPlanExample = new TestPlanExample(); + testPlanExample.createCriteria().andGroupIdEqualTo(testPlanId); + testPlanMapper.selectByExample(testPlanExample).forEach( + item -> scheduleService.deleteByResourceId(testPlanId, TestPlanScheduleJob.getJobKey(testPlanId), TestPlanScheduleJob.getTriggerKey(testPlanId))); } public List listHis(TestPlanExecuteHisPageRequest request) { diff --git a/backend/services/test-plan/src/test/java/io/metersphere/plan/controller/TestPlanExecuteTests.java b/backend/services/test-plan/src/test/java/io/metersphere/plan/controller/TestPlanExecuteTests.java index d45690e0b1..6912a33ce4 100644 --- a/backend/services/test-plan/src/test/java/io/metersphere/plan/controller/TestPlanExecuteTests.java +++ b/backend/services/test-plan/src/test/java/io/metersphere/plan/controller/TestPlanExecuteTests.java @@ -1,15 +1,13 @@ package io.metersphere.plan.controller; -import io.metersphere.plan.domain.TestPlan; -import io.metersphere.plan.domain.TestPlanCollection; -import io.metersphere.plan.domain.TestPlanCollectionExample; -import io.metersphere.plan.domain.TestPlanConfig; +import io.metersphere.plan.domain.*; import io.metersphere.plan.dto.request.TestPlanBatchExecuteRequest; import io.metersphere.plan.dto.request.TestPlanCreateRequest; import io.metersphere.plan.dto.request.TestPlanExecuteRequest; import io.metersphere.plan.mapper.TestPlanCollectionMapper; import io.metersphere.plan.mapper.TestPlanConfigMapper; import io.metersphere.plan.mapper.TestPlanMapper; +import io.metersphere.plan.mapper.TestPlanReportMapper; import io.metersphere.plan.service.TestPlanExecuteService; import io.metersphere.plan.service.TestPlanTestService; import io.metersphere.project.domain.Project; @@ -26,6 +24,7 @@ import jakarta.annotation.Resource; import org.apache.commons.collections4.CollectionUtils; 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.data.redis.core.StringRedisTemplate; @@ -65,6 +64,8 @@ public class TestPlanExecuteTests extends BaseTest { "test-plan-batch-execute:", "test-plan-group-execute:", "test-plan-case-type-execute:", "test-plan-collection-execute:" }; public static final String QUEUE_PREFIX_TEST_PLAN_COLLECTION = "test-plan-collection-execute:"; + @Autowired + private TestPlanReportMapper testPlanReportMapper; @Test @Order(1) @@ -190,19 +191,49 @@ public class TestPlanExecuteTests extends BaseTest { // 串行4个计划组和一个计划 this.executeBatch(batchExecuteIds, ApiBatchRunMode.SERIAL.name()); + for (TestPlan group : testPlanGroupList) { + TestPlanReportExample example = new TestPlanReportExample(); + example.createCriteria().andTestPlanIdEqualTo(group.getId()); + Assertions.assertTrue(testPlanReportMapper.countByExample(example) > 0); + testPlanReportMapper.deleteByExample(example); + } + //并行4个计划组和一个计划 this.executeBatch(batchExecuteIds, ApiBatchRunMode.PARALLEL.name()); - + for (TestPlan group : testPlanGroupList) { + TestPlanReportExample example = new TestPlanReportExample(); + example.createCriteria().andTestPlanIdEqualTo(group.getId()); + Assertions.assertTrue(testPlanReportMapper.countByExample(example) > 0); + testPlanReportMapper.deleteByExample(example); + } //单独串行一个计划组 this.executeOne(allSerialGroup.getId(), ApiBatchRunMode.SERIAL.name()); + TestPlanReportExample example = new TestPlanReportExample(); + example.createCriteria().andTestPlanIdEqualTo(allSerialGroup.getId()); + Assertions.assertTrue(testPlanReportMapper.countByExample(example) > 0); + testPlanReportMapper.deleteByExample(example); + //单独串行一个计划 this.executeOne(noGroupPlan.getId(), ApiBatchRunMode.SERIAL.name()); + example = new TestPlanReportExample(); + example.createCriteria().andTestPlanIdEqualTo(noGroupPlan.getId()); + Assertions.assertTrue(testPlanReportMapper.countByExample(example) > 0); + testPlanReportMapper.deleteByExample(example); //单独并行一个计划组 this.executeOne(allParallelGroup.getId(), ApiBatchRunMode.PARALLEL.name()); + example = new TestPlanReportExample(); + example.createCriteria().andTestPlanIdEqualTo(allParallelGroup.getId()); + Assertions.assertTrue(testPlanReportMapper.countByExample(example) > 0); + testPlanReportMapper.deleteByExample(example); + //单独并行一个计划 this.executeOne(noGroupPlan.getId(), ApiBatchRunMode.PARALLEL.name()); + example = new TestPlanReportExample(); + example.createCriteria().andTestPlanIdEqualTo(noGroupPlan.getId()); + Assertions.assertTrue(testPlanReportMapper.countByExample(example) > 0); + testPlanReportMapper.deleteByExample(example); } private void executeBatch(List execIds, String runMode) throws Exception { 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 b315db31b4..b4145d9313 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 @@ -2171,12 +2171,9 @@ public class TestPlanTests extends BaseTest { @Test @Order(303) public void testCopy() throws Exception { - //1.计划 无用例 - MvcResult mvcResult = this.requestGetWithOkAndReturn(String.format(URL_TEST_PLAN_COPY, "wx_test_plan_id_1")); - String returnStr = mvcResult.getResponse().getContentAsString(); - ResultHolder holder = JSON.parseObject(returnStr, ResultHolder.class); - String returnId = holder.getData().toString(); - Assertions.assertNotNull(returnId); + //1. 已归档的不能再归档计划 无用例 + requestGet(String.format(URL_TEST_PLAN_COPY, "wx_test_plan_id_1")).andExpect(status().is5xxServerError()); + //2.计划 有用例 MvcResult mvcResult1 = this.requestGetWithOkAndReturn(String.format(URL_TEST_PLAN_COPY, "wx_test_plan_id_4"));