fix(测试计划): 复制测试计划时补足日志内容

This commit is contained in:
Jianguo-Genius 2024-06-19 11:24:36 +08:00 committed by 建国
parent 2f31cf385a
commit 6867bd97dd
9 changed files with 188 additions and 177 deletions

View File

@ -0,0 +1,7 @@
███╗ ███╗███████╗████████╗███████╗██████╗ ███████╗██████╗ ██╗ ██╗███████╗██████╗ ███████╗
████╗ ████║██╔════╝╚══██╔══╝██╔════╝██╔══██╗██╔════╝██╔══██╗██║ ██║██╔════╝██╔══██╗██╔════╝
██╔████╔██║█████╗ ██║ █████╗ ██████╔╝███████╗██████╔╝███████║█████╗ ██████╔╝█████╗
██║╚██╔╝██║██╔══╝ ██║ ██╔══╝ ██╔══██╗╚════██║██╔═══╝ ██╔══██║██╔══╝ ██╔══██╗██╔══╝
██║ ╚═╝ ██║███████╗ ██║ ███████╗██║ ██║███████║██║ ██║ ██║███████╗██║ ██║███████╗
╚═╝ ╚═╝╚══════╝ ╚═╝ ╚══════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚══════╝

View File

@ -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";

View File

@ -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());
}

View File

@ -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<String, List<TestPlan>> 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<String, List<TestPlan>> planGroups, TestPlanBatchProcessRequest request, String userId) {
//TODO 批量归档计划组
return 0;
}
/**
* 批量归档计划
*
* @param plans 归档测试计划集合
*/
private int batchArchivedPlan(Map<String, List<TestPlan>> plans, String userId) {
if (plans.containsKey(TestPlanConstants.TEST_PLAN_TYPE_PLAN)) {
List<TestPlan> testPlans = plans.get(TestPlanConstants.TEST_PLAN_TYPE_PLAN);
List<String> 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;
}
}
}

View File

@ -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<TestPlan> testPlanList, String moduleId, String userId) {
List<String> 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<TestPlanCollection> testPlanCollectionList = testPlanCollectionMapper.selectByExample(parentCollectionExample);
if (CollectionUtils.isEmpty(testPlanCollectionList)) {
//自动生成测试规划
Objects.requireNonNull(CommonBeanFactory.getBean(TestPlanService.class)).initDefaultPlanCollection(testPlan.getId(), operator);
} else {
List<TestPlanCollection> 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<TestPlanCollection> 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<String, TestPlanResourceService> 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<TestPlan> 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) {

View File

@ -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());

View File

@ -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<String> batchArchivedIds = request.getSelectIds();
if (CollectionUtils.isNotEmpty(batchArchivedIds)) {
TestPlanExample example = new TestPlanExample();
example.createCriteria().andIdIn(batchArchivedIds).andStatusEqualTo(TestPlanConstants.TEST_PLAN_STATUS_COMPLETED);
List<TestPlan> archivedPlanList = testPlanMapper.selectByExample(example);
Map<String, List<TestPlan>> plans = archivedPlanList.stream().collect(Collectors.groupingBy(TestPlan::getType));
testPlanBatchArchivedService.batchArchived(plans, request, currentUser);
example.createCriteria().andIdIn(batchArchivedIds);
List<TestPlan> 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<TestPlan> 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<TestPlan> childPlan = this.selectNotArchivedChildren(testPlanGroupId);
String groupStatus = TestPlanConstants.TEST_PLAN_STATUS_PREPARED;
// 未开始:计划组为空组内所有计划都是未开始状态
// 已完成:组内计划均为已完成状态
// 进行中:组内计划有未完成的状态
if (CollectionUtils.isNotEmpty(childPlan)) {
List<String> 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<TestPlanExecuteHisDTO> listHis(TestPlanExecuteHisPageRequest request) {

View File

@ -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<String> execIds, String runMode) throws Exception {

View File

@ -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"));