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 BUG_MANAGEMENT_RECYCLE = "BUG_MANAGEMENT_BUG_RECYCLE";
//测试计划 //测试计划
public static final String TEST_PLAN = "TEST_PLAN"; 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_MODULE = "TEST_PLAN_MODULE";
public static final String TEST_PLAN_REPORT = "TEST_PLAN_REPORT"; public static final String TEST_PLAN_REPORT = "TEST_PLAN_REPORT";

View File

@ -201,7 +201,7 @@ public class TestPlanController {
@Operation(summary = "测试计划-批量归档") @Operation(summary = "测试计划-批量归档")
@RequiresPermissions(PermissionConstants.TEST_PLAN_READ_UPDATE) @RequiresPermissions(PermissionConstants.TEST_PLAN_READ_UPDATE)
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project") @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)); testPlanManagementService.checkModuleIsOpen(request.getProjectId(), TestPlanResourceConfig.CHECK_TYPE_PROJECT, Collections.singletonList(TestPlanResourceConfig.CONFIG_TEST_PLAN));
testPlanService.batchArchived(request, SessionUtils.getUserId()); 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; package io.metersphere.plan.service;
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.dto.response.TestPlanResponse; import io.metersphere.plan.dto.response.TestPlanResponse;
import io.metersphere.plan.mapper.ExtTestPlanMapper; import io.metersphere.plan.mapper.ExtTestPlanMapper;
import io.metersphere.plan.mapper.TestPlanCollectionMapper;
import io.metersphere.plan.mapper.TestPlanConfigMapper; import io.metersphere.plan.mapper.TestPlanConfigMapper;
import io.metersphere.plan.mapper.TestPlanMapper; import io.metersphere.plan.mapper.TestPlanMapper;
import io.metersphere.project.utils.NodeSortUtils; 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.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.Translator; import io.metersphere.sdk.util.Translator;
import io.metersphere.system.uid.IDGenerator; import io.metersphere.system.uid.IDGenerator;
import io.metersphere.system.uid.NumGenerator; import io.metersphere.system.uid.NumGenerator;
@ -23,10 +23,7 @@ import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList; import java.util.*;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@Service @Service
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@ -43,6 +40,8 @@ public class TestPlanBatchOperationService extends TestPlanBaseUtilsService {
private TestPlanConfigMapper testPlanConfigMapper; private TestPlanConfigMapper testPlanConfigMapper;
@Autowired @Autowired
private ApplicationContext applicationContext; private ApplicationContext applicationContext;
@Resource
private TestPlanCollectionMapper testPlanCollectionMapper;
public long batchMoveModule(List<TestPlan> testPlanList, String moduleId, String userId) { public long batchMoveModule(List<TestPlan> testPlanList, String moduleId, String userId) {
List<String> movePlanIds = new ArrayList<>(); List<String> movePlanIds = new ArrayList<>();
@ -124,10 +123,11 @@ public class TestPlanBatchOperationService extends TestPlanBaseUtilsService {
*/ */
for (TestPlan copyPlan : copyPlanList) { for (TestPlan copyPlan : copyPlanList) {
if (StringUtils.equalsIgnoreCase(copyPlan.getType(), TestPlanConstants.TEST_PLAN_TYPE_GROUP)) { 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 { } else {
copyCount += this.copyPlan(copyPlan, targetId, targetType, operatorTime, userId); this.copyPlan(copyPlan, targetId, targetType, operatorTime, userId);
} }
copyCount++;
} }
return copyCount; return copyCount;
} }
@ -143,10 +143,10 @@ public class TestPlanBatchOperationService extends TestPlanBaseUtilsService {
* @param operator 操作人 * @param operator 操作人
* @return 复制的数量 * @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)) { 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 moduleId = originalTestPlan.getModuleId();
String groupId = originalTestPlan.getGroupId(); String groupId = originalTestPlan.getGroupId();
@ -194,33 +194,65 @@ public class TestPlanBatchOperationService extends TestPlanBaseUtilsService {
testPlanConfigMapper.insertSelective(newTestPlanConfig); 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); Map<String, TestPlanResourceService> beansOfType = applicationContext.getBeansOfType(TestPlanResourceService.class);
beansOfType.forEach((k, v) -> { beansOfType.forEach((k, v) -> {
v.copyResource(originalTestPlan.getId(), testPlan.getId(), operator, operatorTime); 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的操作. 已归档的无法操作 //测试计划组复制的时候只支持targetType为module的操作. 已归档的无法操作
if (StringUtils.equalsIgnoreCase(targetType, TestPlanConstants.TEST_PLAN_TYPE_GROUP) if (StringUtils.equalsIgnoreCase(targetType, TestPlanConstants.TEST_PLAN_TYPE_GROUP)
|| StringUtils.equalsIgnoreCase(originalGroup.getStatus(), TestPlanConstants.TEST_PLAN_STATUS_ARCHIVED)) { || StringUtils.equalsIgnoreCase(originalGroup.getStatus(), TestPlanConstants.TEST_PLAN_STATUS_ARCHIVED)) {
return 0; throw new MSException(Translator.get("test_plan.group.error"));
} }
super.checkModule(targetId); super.checkModule(targetId);
String moduleId = targetId; String moduleId = targetId;
TestPlanExample example = new TestPlanExample(); TestPlanExample example = new TestPlanExample();
example.createCriteria().andGroupIdEqualTo(originalGroup.getId()); example.createCriteria().andGroupIdEqualTo(originalGroup.getId()).andStatusNotEqualTo(TestPlanConstants.TEST_PLAN_STATUS_ARCHIVED);
example.setOrderByClause("pos asc"); example.setOrderByClause("pos asc");
List<TestPlan> childList = testPlanMapper.selectByExample(example); List<TestPlan> childList = testPlanMapper.selectByExample(example);
int copyCount = 0;
TestPlan testPlanGroup = new TestPlan(); TestPlan testPlanGroup = new TestPlan();
BeanUtils.copyBean(testPlanGroup, originalGroup); BeanUtils.copyBean(testPlanGroup, originalGroup);
testPlanGroup.setId(IDGenerator.nextStr()); testPlanGroup.setId(IDGenerator.nextStr());
@ -232,13 +264,12 @@ public class TestPlanBatchOperationService extends TestPlanBaseUtilsService {
testPlanGroup.setUpdateTime(operatorTime); testPlanGroup.setUpdateTime(operatorTime);
testPlanGroup.setModuleId(moduleId); testPlanGroup.setModuleId(moduleId);
testPlanGroup.setStatus(TestPlanConstants.TEST_PLAN_STATUS_PREPARED); testPlanGroup.setStatus(TestPlanConstants.TEST_PLAN_STATUS_PREPARED);
copyCount += testPlanMapper.insert(testPlanGroup); testPlanMapper.insert(testPlanGroup);
for (TestPlan child : childList) { 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 testPlanGroup;
return copyCount;
} }
private String getCopyName(String name, long oldNum, long newNum) { 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.TestPlan;
import io.metersphere.plan.domain.TestPlanExample; import io.metersphere.plan.domain.TestPlanExample;
import io.metersphere.plan.dto.request.TestPlanBatchEditRequest; import io.metersphere.plan.dto.request.TestPlanBatchEditRequest;
import io.metersphere.plan.dto.request.TestPlanCopyRequest;
import io.metersphere.plan.mapper.TestPlanMapper; import io.metersphere.plan.mapper.TestPlanMapper;
import io.metersphere.project.domain.Project; import io.metersphere.project.domain.Project;
import io.metersphere.project.mapper.ProjectMapper; import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.sdk.constants.HttpMethodConstants; import io.metersphere.sdk.constants.HttpMethodConstants;
import io.metersphere.sdk.constants.TestPlanConstants;
import io.metersphere.sdk.util.JSON; import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.Translator; import io.metersphere.sdk.util.Translator;
import io.metersphere.system.dto.LogInsertModule; import io.metersphere.system.dto.LogInsertModule;
@ -32,7 +30,7 @@ import java.util.stream.Collectors;
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public class TestPlanLogService { public class TestPlanLogService {
private String logModule = OperationLogModule.TEST_PLAN; private String logModule = OperationLogModule.TEST_PLAN_INDEX;
@Resource @Resource
private ProjectMapper projectMapper; private ProjectMapper projectMapper;
@ -48,7 +46,7 @@ public class TestPlanLogService {
.projectId(project.getId()) .projectId(project.getId())
.organizationId(project.getOrganizationId()) .organizationId(project.getOrganizationId())
.type(OperationLogType.UPDATE.name()) .type(OperationLogType.UPDATE.name())
.module(OperationLogModule.TEST_PLAN) .module(logModule)
.sourceId(testPlan.getId()) .sourceId(testPlan.getId())
.content(Translator.get("test_plan_schedule") + ":" + testPlan.getName()) .content(Translator.get("test_plan_schedule") + ":" + testPlan.getName())
.build().getLogDTO(); .build().getLogDTO();
@ -100,7 +98,7 @@ public class TestPlanLogService {
.method(requestMethod) .method(requestMethod)
.path(requestUrl) .path(requestUrl)
.sourceId(newTestPlan.getId()) .sourceId(newTestPlan.getId())
.content(generateTestPlanSimpleContent(newTestPlan, Translator.get("update"))) .content(newTestPlan.getName())
.originalValue(JSON.toJSONBytes(oldTestPlan)) .originalValue(JSON.toJSONBytes(oldTestPlan))
.modifiedValue(JSON.toJSONBytes(newTestPlan)) .modifiedValue(JSON.toJSONBytes(newTestPlan))
.createUser(operator) .createUser(operator)
@ -126,7 +124,7 @@ public class TestPlanLogService {
.method(requestMethod) .method(requestMethod)
.path(requestUrl) .path(requestUrl)
.sourceId(deleteTestPlan.getId()) .sourceId(deleteTestPlan.getId())
.content(generateTestPlanSimpleContent(deleteTestPlan, Translator.get("delete"))) .content(deleteTestPlan.getName())
.originalValue(JSON.toJSONBytes(deleteTestPlan)) .originalValue(JSON.toJSONBytes(deleteTestPlan))
.createUser(operator) .createUser(operator)
.build().getLogDTO(); .build().getLogDTO();
@ -157,25 +155,23 @@ public class TestPlanLogService {
/** /**
* 复制日志 * 复制日志
*
* @param request 请求参数
* @return 日志对象
*/ */
public LogDTO copyLog(TestPlanCopyRequest request) { public void copyLog(TestPlan testPlan, String operator) {
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(request.getId()); if (testPlan != null) {
testPlan.setName(request.getName()); Project project = projectMapper.selectByPrimaryKey(testPlan.getProjectId());
LogDTO dto = new LogDTO( LogDTO dto = new LogDTO(
request.getProjectId(), testPlan.getProjectId(),
null, project.getOrganizationId(),
null, testPlan.getId(),
null, operator,
OperationLogType.COPY.name(), OperationLogType.COPY.name(),
logModule, logModule,
generateTestPlanSimpleContent(testPlan, Translator.get("copy"))); testPlan.getName());
dto.setPath("/test-plan/copy"); dto.setPath("/test-plan/copy");
dto.setMethod(HttpMethodConstants.POST.name()); dto.setMethod(HttpMethodConstants.POST.name());
dto.setOriginalValue(JSON.toJSONBytes(request)); dto.setOriginalValue(JSON.toJSONBytes(testPlan));
return dto; operationLogService.add(dto);
}
} }
/** /**
@ -200,7 +196,7 @@ public class TestPlanLogService {
.method(requestMethod) .method(requestMethod)
.path(requestUrl) .path(requestUrl)
.sourceId(plan.getId()) .sourceId(plan.getId())
.content(generateTestPlanSimpleContent(plan, Translator.get(typeKey))) .content(plan.getName())
.originalValue(JSON.toJSONBytes(plan)) .originalValue(JSON.toJSONBytes(plan))
.createUser(operator) .createUser(operator)
.build().getLogDTO(); .build().getLogDTO();
@ -209,24 +205,6 @@ public class TestPlanLogService {
operationLogService.batchAdd(list); 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(), testPlan.getId(),
null, null,
OperationLogType.UPDATE.name(), OperationLogType.UPDATE.name(),
OperationLogModule.TEST_PLAN, logModule,
testPlan.getName()); testPlan.getName());
dto.setPath("/test-plan/batch-edit"); dto.setPath("/test-plan/batch-edit");
dto.setMethod(HttpMethodConstants.POST.name()); dto.setMethod(HttpMethodConstants.POST.name());

View File

@ -75,8 +75,6 @@ public class TestPlanService extends TestPlanBaseUtilsService {
@Resource @Resource
private TestPlanBatchOperationService testPlanBatchOperationService; private TestPlanBatchOperationService testPlanBatchOperationService;
@Resource @Resource
private TestPlanBatchArchivedService testPlanBatchArchivedService;
@Resource
private TestPlanStatisticsService testPlanStatisticsService; private TestPlanStatisticsService testPlanStatisticsService;
@Resource @Resource
private TestPlanCaseService testPlanCaseService; private TestPlanCaseService testPlanCaseService;
@ -113,6 +111,12 @@ public class TestPlanService extends TestPlanBaseUtilsService {
TestPlan testPlan = savePlanDTO(testPlanCreateRequest, operator); TestPlan testPlan = savePlanDTO(testPlanCreateRequest, operator);
//自动生成测试规划 //自动生成测试规划
this.initDefaultPlanCollection(testPlan.getId(), 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); testPlanLogService.saveAddLog(testPlan, operator, requestUrl, requestMethod);
return testPlan; return testPlan;
} }
@ -152,9 +156,6 @@ public class TestPlanService extends TestPlanBaseUtilsService {
testPlanConfig.setRepeatCase(createOrCopyRequest.isRepeatCase()); testPlanConfig.setRepeatCase(createOrCopyRequest.isRepeatCase());
testPlanConfig.setPassThreshold(createOrCopyRequest.getPassThreshold()); testPlanConfig.setPassThreshold(createOrCopyRequest.getPassThreshold());
//正式版本不再支持这种操作
// handleAssociateCase(createOrCopyRequest.getBaseAssociateCaseRequest(), operator, createTestPlan);
testPlanMapper.insert(createTestPlan); testPlanMapper.insert(createTestPlan);
testPlanConfigMapper.insertSelective(testPlanConfig); testPlanConfigMapper.insertSelective(testPlanConfig);
return createTestPlan; return createTestPlan;
@ -202,13 +203,17 @@ public class TestPlanService extends TestPlanBaseUtilsService {
public void delete(String id, String operator, String requestUrl, String requestMethod) { public void delete(String id, String operator, String requestUrl, String requestMethod) {
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(id); TestPlan testPlan = testPlanMapper.selectByPrimaryKey(id);
if (StringUtils.equals(testPlan.getType(), TestPlanConstants.TEST_PLAN_TYPE_GROUP)) { if (StringUtils.equals(testPlan.getType(), TestPlanConstants.TEST_PLAN_TYPE_GROUP)) {
// 计划组的删除暂时预留
this.deleteGroupByList(Collections.singletonList(testPlan.getId())); this.deleteGroupByList(Collections.singletonList(testPlan.getId()));
} else { } else {
testPlanMapper.deleteByPrimaryKey(id); testPlanMapper.deleteByPrimaryKey(id);
//级联删除 //级联删除
TestPlanReportService testPlanReportService = CommonBeanFactory.getBean(TestPlanReportService.class); TestPlanReportService testPlanReportService = CommonBeanFactory.getBean(TestPlanReportService.class);
this.cascadeDeleteTestPlanIds(Collections.singletonList(id), testPlanReportService); 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); testPlanLogService.saveDeleteLog(testPlan, operator, requestUrl, requestMethod);
@ -357,7 +362,9 @@ public class TestPlanService extends TestPlanBaseUtilsService {
updateTestPlan.setPlannedStartTime(request.getPlannedStartTime()); updateTestPlan.setPlannedStartTime(request.getPlannedStartTime());
updateTestPlan.setPlannedEndTime(request.getPlannedEndTime()); updateTestPlan.setPlannedEndTime(request.getPlannedEndTime());
updateTestPlan.setDescription(request.getDescription()); updateTestPlan.setDescription(request.getDescription());
updateTestPlan.setGroupId(request.getGroupId()); if (CollectionUtils.isNotEmpty(request.getTags())) {
updateTestPlan.setTags(new ArrayList<>(request.getTags()));
}
updateTestPlan.setType(testPlan.getType()); updateTestPlan.setType(testPlan.getType());
testPlanMapper.updateByPrimaryKeySelective(updateTestPlan); testPlanMapper.updateByPrimaryKeySelective(updateTestPlan);
} }
@ -406,12 +413,16 @@ public class TestPlanService extends TestPlanBaseUtilsService {
if (StringUtils.equalsAnyIgnoreCase(testPlan.getType(), TestPlanConstants.TEST_PLAN_TYPE_GROUP)) { if (StringUtils.equalsAnyIgnoreCase(testPlan.getType(), TestPlanConstants.TEST_PLAN_TYPE_GROUP)) {
//测试计划组归档 //测试计划组归档
updateGroupStatus(testPlan.getId(), userId); 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)) { } 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.setStatus(TestPlanConstants.TEST_PLAN_STATUS_ARCHIVED);
testPlan.setUpdateUser(userId); testPlan.setUpdateUser(userId);
testPlan.setUpdateTime(System.currentTimeMillis()); testPlan.setUpdateTime(System.currentTimeMillis());
testPlanMapper.updateByPrimaryKeySelective(testPlan); testPlanMapper.updateByPrimaryKeySelective(testPlan);
//关闭定时任务
this.deleteScheduleConfig(testPlan.getId());
} else { } else {
throw new MSException(Translator.get("test_plan.cannot.archived")); throw new MSException(Translator.get("test_plan.cannot.archived"));
} }
@ -424,14 +435,16 @@ public class TestPlanService extends TestPlanBaseUtilsService {
* @param request 批量请求参数 * @param request 批量请求参数
* @param currentUser 当前用户 * @param currentUser 当前用户
*/ */
public void batchArchived(TestPlanBatchRequest request, String currentUser) { public void batchArchived(TestPlanBatchProcessRequest request, String currentUser) {
List<String> batchArchivedIds = request.getSelectIds(); List<String> batchArchivedIds = request.getSelectIds();
if (CollectionUtils.isNotEmpty(batchArchivedIds)) { if (CollectionUtils.isNotEmpty(batchArchivedIds)) {
TestPlanExample example = new TestPlanExample(); TestPlanExample example = new TestPlanExample();
example.createCriteria().andIdIn(batchArchivedIds).andStatusEqualTo(TestPlanConstants.TEST_PLAN_STATUS_COMPLETED); example.createCriteria().andIdIn(batchArchivedIds);
List<TestPlan> archivedPlanList = testPlanMapper.selectByExample(example); List<TestPlan> archivedPlanList = testPlanMapper.selectByExample(example).stream().filter(
Map<String, List<TestPlan>> plans = archivedPlanList.stream().collect(Collectors.groupingBy(TestPlan::getType)); testPlan -> StringUtils.equalsAnyIgnoreCase(testPlan.getType(), TestPlanConstants.TEST_PLAN_TYPE_GROUP)
testPlanBatchArchivedService.batchArchived(plans, request, currentUser); || (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"); 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) { public long copy(String testPlanId, String userId) {
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(testPlanId); TestPlan testPlan = testPlanMapper.selectByPrimaryKey(testPlanId);
TestPlan copyPlan = null;
if (StringUtils.equalsIgnoreCase(testPlan.getType(), TestPlanConstants.TEST_PLAN_TYPE_GROUP)) { 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 { } 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); testPlan = testPlanMapper.selectByPrimaryKey(testPlanId);
if (!StringUtils.equalsIgnoreCase(testPlan.getGroupId(), TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID)) { if (!StringUtils.equalsIgnoreCase(testPlan.getGroupId(), TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID)) {
//该测试计划是测试计划组内的子计划 要同步计算测试计划组的状态 this.updateTestPlanGroupStatus(testPlan.getGroupId());
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);
if (StringUtils.equalsIgnoreCase(updateGroupPlan.getStatus(), TestPlanConstants.TEST_PLAN_STATUS_COMPLETED)) { private void updateTestPlanGroupStatus(String testPlanGroupId) {
extTestPlanMapper.setActualEndTime(testPlan.getGroupId(), System.currentTimeMillis()); //该测试计划是测试计划组内的子计划 要同步计算测试计划组的状态
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) { public void refreshTestPlanStatus(String testPlanId) {
@ -875,6 +906,12 @@ public class TestPlanService extends TestPlanBaseUtilsService {
public void deleteScheduleConfig(String testPlanId) { public void deleteScheduleConfig(String testPlanId) {
scheduleService.deleteByResourceId(testPlanId, TestPlanScheduleJob.getJobKey(testPlanId), TestPlanScheduleJob.getTriggerKey(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) { public List<TestPlanExecuteHisDTO> listHis(TestPlanExecuteHisPageRequest request) {

View File

@ -1,15 +1,13 @@
package io.metersphere.plan.controller; package io.metersphere.plan.controller;
import io.metersphere.plan.domain.TestPlan; import io.metersphere.plan.domain.*;
import io.metersphere.plan.domain.TestPlanCollection;
import io.metersphere.plan.domain.TestPlanCollectionExample;
import io.metersphere.plan.domain.TestPlanConfig;
import io.metersphere.plan.dto.request.TestPlanBatchExecuteRequest; import io.metersphere.plan.dto.request.TestPlanBatchExecuteRequest;
import io.metersphere.plan.dto.request.TestPlanCreateRequest; import io.metersphere.plan.dto.request.TestPlanCreateRequest;
import io.metersphere.plan.dto.request.TestPlanExecuteRequest; import io.metersphere.plan.dto.request.TestPlanExecuteRequest;
import io.metersphere.plan.mapper.TestPlanCollectionMapper; import io.metersphere.plan.mapper.TestPlanCollectionMapper;
import io.metersphere.plan.mapper.TestPlanConfigMapper; import io.metersphere.plan.mapper.TestPlanConfigMapper;
import io.metersphere.plan.mapper.TestPlanMapper; import io.metersphere.plan.mapper.TestPlanMapper;
import io.metersphere.plan.mapper.TestPlanReportMapper;
import io.metersphere.plan.service.TestPlanExecuteService; import io.metersphere.plan.service.TestPlanExecuteService;
import io.metersphere.plan.service.TestPlanTestService; import io.metersphere.plan.service.TestPlanTestService;
import io.metersphere.project.domain.Project; import io.metersphere.project.domain.Project;
@ -26,6 +24,7 @@ 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;
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.data.redis.core.StringRedisTemplate; 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:" "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:"; public static final String QUEUE_PREFIX_TEST_PLAN_COLLECTION = "test-plan-collection-execute:";
@Autowired
private TestPlanReportMapper testPlanReportMapper;
@Test @Test
@Order(1) @Order(1)
@ -190,19 +191,49 @@ public class TestPlanExecuteTests extends BaseTest {
// 串行4个计划组和一个计划 // 串行4个计划组和一个计划
this.executeBatch(batchExecuteIds, ApiBatchRunMode.SERIAL.name()); 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个计划组和一个计划 //并行4个计划组和一个计划
this.executeBatch(batchExecuteIds, ApiBatchRunMode.PARALLEL.name()); 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()); 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()); 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()); 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()); 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 { private void executeBatch(List<String> execIds, String runMode) throws Exception {

View File

@ -2171,12 +2171,9 @@ public class TestPlanTests extends BaseTest {
@Test @Test
@Order(303) @Order(303)
public void testCopy() throws Exception { public void testCopy() throws Exception {
//1.计划 无用例 //1. 已归档的不能再归档计划 无用例
MvcResult mvcResult = this.requestGetWithOkAndReturn(String.format(URL_TEST_PLAN_COPY, "wx_test_plan_id_1")); requestGet(String.format(URL_TEST_PLAN_COPY, "wx_test_plan_id_1")).andExpect(status().is5xxServerError());
String returnStr = mvcResult.getResponse().getContentAsString();
ResultHolder holder = JSON.parseObject(returnStr, ResultHolder.class);
String returnId = holder.getData().toString();
Assertions.assertNotNull(returnId);
//2.计划 有用例 //2.计划 有用例
MvcResult mvcResult1 = this.requestGetWithOkAndReturn(String.format(URL_TEST_PLAN_COPY, "wx_test_plan_id_4")); MvcResult mvcResult1 = this.requestGetWithOkAndReturn(String.format(URL_TEST_PLAN_COPY, "wx_test_plan_id_4"));