feat(测试计划): 测试计划批量执行方法开发
This commit is contained in:
parent
b828dfec49
commit
bcb92cb79e
|
@ -8,16 +8,28 @@ import lombok.NoArgsConstructor;
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
public class TestPlanExecutionQueue {
|
public class TestPlanExecutionQueue {
|
||||||
private String queueId;
|
|
||||||
private String parentQueueId;
|
|
||||||
private String testPlanId;
|
|
||||||
//顺序
|
//顺序
|
||||||
private long pos;
|
private long pos;
|
||||||
|
//创建人
|
||||||
|
private String createUser;
|
||||||
|
//创建时间
|
||||||
|
private long createTime;
|
||||||
|
//队列ID
|
||||||
|
private String queueId;
|
||||||
|
// 队列类型
|
||||||
|
private String queueType;
|
||||||
|
//父类队列ID
|
||||||
|
private String parentQueueId;
|
||||||
|
//父类队列ID
|
||||||
|
private String parentQueueType;
|
||||||
|
//资源ID(测试集/测试计划/测试计划组)
|
||||||
|
private String sourceID;
|
||||||
//执行模式
|
//执行模式
|
||||||
private String runMode;
|
private String runMode;
|
||||||
//执行来源
|
//执行来源
|
||||||
private String executionSource;
|
private String executionSource;
|
||||||
|
//预生成报告ID
|
||||||
private String prepareReportId;
|
private String prepareReportId;
|
||||||
private String createUser;
|
|
||||||
private long createTime;
|
private boolean isLastNode;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,14 @@ package io.metersphere.plan.controller;
|
||||||
|
|
||||||
import com.github.pagehelper.Page;
|
import com.github.pagehelper.Page;
|
||||||
import com.github.pagehelper.PageHelper;
|
import com.github.pagehelper.PageHelper;
|
||||||
|
import io.metersphere.plan.constants.TestPlanResourceConfig;
|
||||||
import io.metersphere.plan.dto.request.*;
|
import io.metersphere.plan.dto.request.*;
|
||||||
import io.metersphere.plan.dto.response.TestPlanApiCasePageResponse;
|
import io.metersphere.plan.dto.response.TestPlanApiCasePageResponse;
|
||||||
import io.metersphere.plan.dto.response.TestPlanAssociationResponse;
|
import io.metersphere.plan.dto.response.TestPlanAssociationResponse;
|
||||||
|
import io.metersphere.plan.dto.response.TestPlanOperationResponse;
|
||||||
import io.metersphere.plan.service.TestPlanApiCaseLogService;
|
import io.metersphere.plan.service.TestPlanApiCaseLogService;
|
||||||
import io.metersphere.plan.service.TestPlanApiCaseService;
|
import io.metersphere.plan.service.TestPlanApiCaseService;
|
||||||
|
import io.metersphere.plan.service.TestPlanManagementService;
|
||||||
import io.metersphere.plan.service.TestPlanService;
|
import io.metersphere.plan.service.TestPlanService;
|
||||||
import io.metersphere.sdk.constants.HttpMethodConstants;
|
import io.metersphere.sdk.constants.HttpMethodConstants;
|
||||||
import io.metersphere.sdk.constants.PermissionConstants;
|
import io.metersphere.sdk.constants.PermissionConstants;
|
||||||
|
@ -28,6 +31,7 @@ import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -39,8 +43,18 @@ public class TestPlanApiCaseController {
|
||||||
@Resource
|
@Resource
|
||||||
private TestPlanApiCaseService testPlanApiCaseService;
|
private TestPlanApiCaseService testPlanApiCaseService;
|
||||||
@Resource
|
@Resource
|
||||||
|
private TestPlanManagementService testPlanManagementService;
|
||||||
|
@Resource
|
||||||
private TestPlanService testPlanService;
|
private TestPlanService testPlanService;
|
||||||
|
|
||||||
|
@PostMapping(value = "/sort")
|
||||||
|
@Operation(summary = "测试计划功能用例-功能用例拖拽排序")
|
||||||
|
@RequiresPermissions(PermissionConstants.TEST_PLAN_READ_UPDATE)
|
||||||
|
@CheckOwner(resourceId = "#request.getTestPlanId()", resourceType = "test_plan")
|
||||||
|
public TestPlanOperationResponse sortNode(@Validated @RequestBody ResourceSortRequest request) {
|
||||||
|
testPlanManagementService.checkModuleIsOpen(request.getTestCollectionId(), TestPlanResourceConfig.CHECK_TYPE_TEST_PLAN, Collections.singletonList(TestPlanResourceConfig.CONFIG_TEST_PLAN_FUNCTIONAL_CASE));
|
||||||
|
return testPlanApiCaseService.sortNode(request, new LogInsertModule(SessionUtils.getUserId(), "/test-plan/api/case/sort", HttpMethodConstants.POST.name()));
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping("/page")
|
@PostMapping("/page")
|
||||||
@Operation(summary = "测试计划-已关联接口用例列表分页查询")
|
@Operation(summary = "测试计划-已关联接口用例列表分页查询")
|
||||||
|
|
|
@ -1,11 +1,16 @@
|
||||||
package io.metersphere.plan.service;
|
package io.metersphere.plan.service;
|
||||||
|
|
||||||
import io.metersphere.plan.domain.TestPlan;
|
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.dto.request.TestPlanBatchExecuteRequest;
|
import io.metersphere.plan.dto.request.TestPlanBatchExecuteRequest;
|
||||||
import io.metersphere.plan.dto.request.TestPlanExecuteRequest;
|
import io.metersphere.plan.dto.request.TestPlanExecuteRequest;
|
||||||
import io.metersphere.plan.enums.TestPlanExecuteQueueType;
|
import io.metersphere.plan.mapper.TestPlanCollectionMapper;
|
||||||
|
import io.metersphere.plan.mapper.TestPlanConfigMapper;
|
||||||
import io.metersphere.plan.mapper.TestPlanMapper;
|
import io.metersphere.plan.mapper.TestPlanMapper;
|
||||||
import io.metersphere.sdk.constants.ApiBatchRunMode;
|
import io.metersphere.sdk.constants.ApiBatchRunMode;
|
||||||
|
import io.metersphere.sdk.constants.CaseType;
|
||||||
import io.metersphere.sdk.constants.TestPlanConstants;
|
import io.metersphere.sdk.constants.TestPlanConstants;
|
||||||
import io.metersphere.sdk.dto.queue.TestPlanExecutionQueue;
|
import io.metersphere.sdk.dto.queue.TestPlanExecutionQueue;
|
||||||
import io.metersphere.sdk.exception.MSException;
|
import io.metersphere.sdk.exception.MSException;
|
||||||
|
@ -29,73 +34,41 @@ public class TestPlanExecuteService {
|
||||||
@Resource
|
@Resource
|
||||||
private TestPlanMapper testPlanMapper;
|
private TestPlanMapper testPlanMapper;
|
||||||
@Resource
|
@Resource
|
||||||
|
private TestPlanConfigMapper testPlanConfigMapper;
|
||||||
|
@Resource
|
||||||
private TestPlanService testPlanService;
|
private TestPlanService testPlanService;
|
||||||
|
@Resource
|
||||||
|
private TestPlanCollectionMapper testPlanCollectionMapper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private RedisTemplate<String, String> redisTemplate;
|
private RedisTemplate<String, String> redisTemplate;
|
||||||
|
|
||||||
public static final String QUEUE_PREFIX_TEST_PLAN = "test-plan-execute:";
|
public static final String QUEUE_PREFIX_TEST_PLAN_BATCH = "test-plan-batch-execute:";
|
||||||
public static final String QUEUE_PREFIX_TEST_PLAN_GROUP = "test-plan-group-execute:";
|
public static final String QUEUE_PREFIX_TEST_PLAN_GROUP = "test-plan-group-execute:";
|
||||||
public static final String QUEUE_PREFIX_TEST_COLLECTION = "test-collection-execute:";
|
public static final String QUEUE_PREFIX_TEST_PLAN_COLLECTION = "test-plan-collection-execute:";
|
||||||
|
public static final String QUEUE_PREFIX_TEST_CASE = "test-plan-collection-execute:";
|
||||||
public String executeTestPlan(TestPlan testPlan, String executionSource, String userId) {
|
|
||||||
//todo 查询执行配置,配置下一步的队列
|
|
||||||
|
|
||||||
return "报告ID";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 预执行执行测试计划
|
|
||||||
*/
|
|
||||||
private String prepareExecuteTestPlan(TestPlan testPlan, String parentQueueId, String runMode, String executionSource, String userId) {
|
|
||||||
if (testPlan == null || StringUtils.equalsIgnoreCase(testPlan.getStatus(), TestPlanConstants.TEST_PLAN_STATUS_ARCHIVED)) {
|
|
||||||
throw new MSException("test_plan.error");
|
|
||||||
}
|
|
||||||
if (StringUtils.equalsIgnoreCase(testPlan.getType(), TestPlanConstants.TEST_PLAN_TYPE_GROUP)) {
|
|
||||||
List<TestPlan> children = testPlanService.selectNotArchivedChildren(testPlan.getId());
|
|
||||||
|
|
||||||
long pos = 0;
|
|
||||||
List<TestPlanExecutionQueue> childrenQueue = new ArrayList<>();
|
|
||||||
for (TestPlan child : children) {
|
|
||||||
childrenQueue.add(
|
|
||||||
new TestPlanExecutionQueue(child.getGroupId(), parentQueueId, child.getId(), pos++, runMode, executionSource, IDGenerator.nextStr(), userId, System.currentTimeMillis())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StringUtils.equalsIgnoreCase(runMode, ApiBatchRunMode.SERIAL.name())) {
|
|
||||||
//串行
|
|
||||||
childrenQueue.forEach(childQueue -> {
|
|
||||||
redisTemplate.opsForList().rightPush(QUEUE_PREFIX_TEST_PLAN_GROUP + testPlan.getId(), JSON.toJSONString(childrenQueue));
|
|
||||||
});
|
|
||||||
executeNextTestPlanByGroupQueueId(testPlan.getId(), parentQueueId);
|
|
||||||
} else {
|
|
||||||
//并行
|
|
||||||
childrenQueue.forEach(childQueue -> {
|
|
||||||
executeTestPlan(testPlanMapper.selectByPrimaryKey(childQueue.getTestPlanId()), childQueue.getExecutionSource(), childQueue.getCreateUser());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
} else {
|
|
||||||
return this.executeTestPlan(testPlan, executionSource, userId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
//单独执行测试计划
|
||||||
/**
|
/**
|
||||||
* 单个执行测试计划
|
* 单个执行测试计划
|
||||||
*/
|
*/
|
||||||
public String singleExecuteTestPlan(TestPlanExecuteRequest request, String userId) {
|
public String singleExecuteTestPlan(TestPlanExecuteRequest request, String userId) {
|
||||||
return prepareExecuteTestPlan(testPlanMapper.selectByPrimaryKey(request.getExecuteId()), null, request.getRunMode(), request.getExecutionSource(), userId);
|
TestPlanExecutionQueue executionQueue = new TestPlanExecutionQueue();
|
||||||
|
executionQueue.setSourceID(request.getExecuteId());
|
||||||
|
executionQueue.setRunMode(request.getRunMode());
|
||||||
|
executionQueue.setExecutionSource(request.getExecutionSource());
|
||||||
|
executionQueue.setCreateUser(userId);
|
||||||
|
executionQueue.setPrepareReportId(IDGenerator.nextStr());
|
||||||
|
return executeTestPlanOrGroup(executionQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
//批量执行测试计划
|
||||||
* 批量执行测试计划
|
|
||||||
*/
|
|
||||||
public void batchExecuteTestPlan(TestPlanBatchExecuteRequest request, String userId) {
|
public void batchExecuteTestPlan(TestPlanBatchExecuteRequest request, String userId) {
|
||||||
List<String> rightfulIds = testPlanService.selectRightfulIds(request.getExecuteIds());
|
List<String> rightfulIds = testPlanService.selectRightfulIds(request.getExecuteIds());
|
||||||
if (CollectionUtils.isNotEmpty(rightfulIds)) {
|
if (CollectionUtils.isNotEmpty(rightfulIds)) {
|
||||||
|
|
||||||
String runMode = request.getRunMode();
|
String runMode = request.getRunMode();
|
||||||
String queueId = IDGenerator.nextStr();
|
String queueId = IDGenerator.nextStr();
|
||||||
|
String queueType = QUEUE_PREFIX_TEST_PLAN_BATCH;
|
||||||
long pos = 0;
|
long pos = 0;
|
||||||
List<TestPlanExecutionQueue> testPlanExecutionQueues = new ArrayList<>();
|
List<TestPlanExecutionQueue> testPlanExecutionQueues = new ArrayList<>();
|
||||||
|
|
||||||
|
@ -103,70 +76,237 @@ public class TestPlanExecuteService {
|
||||||
for (String testPlanId : request.getExecuteIds()) {
|
for (String testPlanId : request.getExecuteIds()) {
|
||||||
if (rightfulIds.contains(testPlanId)) {
|
if (rightfulIds.contains(testPlanId)) {
|
||||||
testPlanExecutionQueues.add(
|
testPlanExecutionQueues.add(
|
||||||
new TestPlanExecutionQueue(queueId, null, testPlanId, pos++, runMode, request.getExecutionSource(), IDGenerator.nextStr(), userId, System.currentTimeMillis())
|
new TestPlanExecutionQueue(
|
||||||
|
pos++,
|
||||||
|
userId,
|
||||||
|
System.currentTimeMillis(),
|
||||||
|
queueId,
|
||||||
|
queueType,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
testPlanId,
|
||||||
|
runMode,
|
||||||
|
request.getExecutionSource(),
|
||||||
|
IDGenerator.nextStr(),
|
||||||
|
false
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
testPlanExecutionQueues.forEach(testPlanExecutionQueue -> {
|
||||||
|
redisTemplate.opsForList().rightPush(testPlanExecutionQueue.getQueueType() + testPlanExecutionQueue.getQueueId(), JSON.toJSONString(testPlanExecutionQueue));
|
||||||
|
});
|
||||||
if (StringUtils.equalsIgnoreCase(request.getRunMode(), ApiBatchRunMode.SERIAL.name())) {
|
if (StringUtils.equalsIgnoreCase(request.getRunMode(), ApiBatchRunMode.SERIAL.name())) {
|
||||||
//串行
|
//串行
|
||||||
testPlanExecutionQueues.forEach(testPlanExecutionQueue -> {
|
TestPlanExecutionQueue nextQueue = this.getNextQueue(queueId, queueType);
|
||||||
redisTemplate.opsForList().rightPush(QUEUE_PREFIX_TEST_PLAN + queueId, JSON.toJSONString(testPlanExecutionQueue));
|
executeTestPlanOrGroup(nextQueue);
|
||||||
});
|
|
||||||
executeNextTestPlanByQueueId(queueId);
|
|
||||||
} else {
|
} else {
|
||||||
//并行
|
//并行
|
||||||
testPlanExecutionQueues.forEach(testPlanExecutionQueue -> {
|
testPlanExecutionQueues.forEach(testPlanExecutionQueue -> {
|
||||||
prepareExecuteTestPlan(testPlanMapper.selectByPrimaryKey(testPlanExecutionQueue.getTestPlanId()),
|
executeTestPlanOrGroup(testPlanExecutionQueue);
|
||||||
null,
|
|
||||||
testPlanExecutionQueue.getRunMode(),
|
|
||||||
testPlanExecutionQueue.getExecutionSource(),
|
|
||||||
testPlanExecutionQueue.getCreateUser());
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//执行下一个测试计划组节点的测试计划
|
//执行测试计划组
|
||||||
private void executeNextTestPlanByGroupQueueId(String groupQueueId, String parentQueueId) {
|
private String executeTestPlanOrGroup(TestPlanExecutionQueue executionQueue) {
|
||||||
TestPlanExecutionQueue nextQueue = getNextDetail(groupQueueId, QUEUE_PREFIX_TEST_PLAN_GROUP, TestPlanExecutionQueue.class);
|
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(executionQueue.getSourceID());
|
||||||
|
if (testPlan == null || StringUtils.equalsIgnoreCase(testPlan.getStatus(), TestPlanConstants.TEST_PLAN_STATUS_ARCHIVED)) {
|
||||||
|
throw new MSException("test_plan.error");
|
||||||
|
}
|
||||||
|
if (StringUtils.equalsIgnoreCase(testPlan.getType(), TestPlanConstants.TEST_PLAN_TYPE_GROUP)) {
|
||||||
|
List<TestPlan> children = testPlanService.selectNotArchivedChildren(testPlan.getId());
|
||||||
|
long pos = 0;
|
||||||
|
List<TestPlanExecutionQueue> childrenQueue = new ArrayList<>();
|
||||||
|
String queueId = IDGenerator.nextStr();
|
||||||
|
String queueType = QUEUE_PREFIX_TEST_PLAN_GROUP;
|
||||||
|
for (TestPlan child : children) {
|
||||||
|
childrenQueue.add(
|
||||||
|
new TestPlanExecutionQueue(
|
||||||
|
pos++,
|
||||||
|
executionQueue.getCreateUser(),
|
||||||
|
System.currentTimeMillis(),
|
||||||
|
queueId,
|
||||||
|
queueType,
|
||||||
|
executionQueue.getQueueId(),
|
||||||
|
executionQueue.getQueueType(),
|
||||||
|
child.getId(),
|
||||||
|
executionQueue.getRunMode(),
|
||||||
|
executionQueue.getExecutionSource(),
|
||||||
|
IDGenerator.nextStr(),
|
||||||
|
false
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
childrenQueue.forEach(childQueue -> {
|
||||||
|
redisTemplate.opsForList().rightPush(childQueue.getQueueType() + childQueue.getQueueId(), JSON.toJSONString(childQueue));
|
||||||
|
});
|
||||||
|
if (StringUtils.equalsIgnoreCase(executionQueue.getRunMode(), ApiBatchRunMode.SERIAL.name())) {
|
||||||
|
//串行
|
||||||
|
TestPlanExecutionQueue nextQueue = this.getNextQueue(queueId, queueType);
|
||||||
|
executeTestPlan(nextQueue);
|
||||||
|
} else {
|
||||||
|
//并行
|
||||||
|
childrenQueue.forEach(childQueue -> {
|
||||||
|
executeTestPlan(childQueue);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return executionQueue.getPrepareReportId();
|
||||||
|
} else {
|
||||||
|
return this.executeTestPlan(executionQueue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//执行测试计划
|
||||||
|
public String executeTestPlan(TestPlanExecutionQueue executionQueue) {
|
||||||
|
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(executionQueue.getSourceID());
|
||||||
|
TestPlanCollectionExample testPlanCollectionExample = new TestPlanCollectionExample();
|
||||||
|
testPlanCollectionExample.createCriteria().andTestPlanIdEqualTo(testPlan.getId());
|
||||||
|
testPlanCollectionExample.setOrderByClause("pos asc");
|
||||||
|
//过滤掉功能用例的测试集
|
||||||
|
List<TestPlanCollection> testPlanCollectionList = testPlanCollectionMapper.selectByExample(testPlanCollectionExample).stream().filter(
|
||||||
|
testPlanCollection -> !StringUtils.equalsIgnoreCase(testPlanCollection.getType(), CaseType.FUNCTIONAL_CASE.getKey())
|
||||||
|
).toList();
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
TestPlanConfig testPlanConfig = testPlanConfigMapper.selectByPrimaryKey(testPlan.getId());
|
||||||
|
String runMode = StringUtils.isBlank(testPlanConfig.getCaseRunMode()) ? ApiBatchRunMode.SERIAL.name() : testPlanConfig.getCaseRunMode();
|
||||||
|
|
||||||
|
String queueId = IDGenerator.nextStr();
|
||||||
|
String queueType = QUEUE_PREFIX_TEST_PLAN_COLLECTION;
|
||||||
|
List<TestPlanExecutionQueue> childrenQueue = new ArrayList<>();
|
||||||
|
for (TestPlanCollection collection : testPlanCollectionList) {
|
||||||
|
childrenQueue.add(
|
||||||
|
new TestPlanExecutionQueue(
|
||||||
|
pos++,
|
||||||
|
executionQueue.getCreateUser(),
|
||||||
|
System.currentTimeMillis(),
|
||||||
|
queueId,
|
||||||
|
queueType,
|
||||||
|
executionQueue.getQueueId(),
|
||||||
|
executionQueue.getQueueType(),
|
||||||
|
collection.getId(),
|
||||||
|
executionQueue.getRunMode(),
|
||||||
|
executionQueue.getExecutionSource(),
|
||||||
|
IDGenerator.nextStr(),
|
||||||
|
false)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
childrenQueue.forEach(childQueue -> {
|
||||||
|
redisTemplate.opsForList().rightPush(childQueue.getQueueType() + childQueue.getQueueId(), JSON.toJSONString(childQueue));
|
||||||
|
});
|
||||||
|
|
||||||
|
// todo Song-cc 这里是否要生成测试计划报告,并且记录测试计划里用例的执行信息?
|
||||||
|
|
||||||
|
//开始根据测试计划集合执行测试用例
|
||||||
|
if (StringUtils.equalsIgnoreCase(runMode, ApiBatchRunMode.SERIAL.name())) {
|
||||||
|
//串行
|
||||||
|
TestPlanExecutionQueue nextQueue = this.getNextQueue(queueId, queueType);
|
||||||
|
this.executeByTestPlanCollection(nextQueue);
|
||||||
|
} else {
|
||||||
|
//并行
|
||||||
|
childrenQueue.forEach(childQueue -> {
|
||||||
|
this.executeByTestPlanCollection(childQueue);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return executionQueue.getPrepareReportId();
|
||||||
|
}
|
||||||
|
|
||||||
|
//执行测试集
|
||||||
|
private void executeByTestPlanCollection(TestPlanExecutionQueue executionQueue) {
|
||||||
|
TestPlanCollection parentCollection = testPlanCollectionMapper.selectByPrimaryKey(executionQueue.getParentQueueId());
|
||||||
|
TestPlanCollectionExample example = new TestPlanCollectionExample();
|
||||||
|
example.createCriteria().andParentIdEqualTo(executionQueue.getSourceID());
|
||||||
|
List<TestPlanCollection> childrenList = testPlanCollectionMapper.selectByExample(example);
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
List<TestPlanExecutionQueue> childrenQueue = new ArrayList<>();
|
||||||
|
|
||||||
|
String queueId = IDGenerator.nextStr();
|
||||||
|
String queueType = QUEUE_PREFIX_TEST_CASE;
|
||||||
|
for (TestPlanCollection collection : childrenList) {
|
||||||
|
childrenQueue.add(
|
||||||
|
new TestPlanExecutionQueue(
|
||||||
|
pos++,
|
||||||
|
executionQueue.getCreateUser(),
|
||||||
|
System.currentTimeMillis(),
|
||||||
|
queueId,
|
||||||
|
queueType,
|
||||||
|
executionQueue.getQueueId(),
|
||||||
|
executionQueue.getQueueType(),
|
||||||
|
collection.getId(),
|
||||||
|
executionQueue.getRunMode(),
|
||||||
|
executionQueue.getExecutionSource(),
|
||||||
|
IDGenerator.nextStr(),
|
||||||
|
false)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
childrenQueue.forEach(childQueue -> {
|
||||||
|
redisTemplate.opsForList().rightPush(childQueue.getQueueType() + childQueue.getQueueId(), JSON.toJSONString(childQueue));
|
||||||
|
});
|
||||||
|
if (StringUtils.equalsIgnoreCase(parentCollection.getExecuteMethod(), ApiBatchRunMode.SERIAL.name())) {
|
||||||
|
//串行
|
||||||
|
TestPlanExecutionQueue nextQueue = this.getNextQueue(queueId, queueType);
|
||||||
|
this.executeCase(nextQueue);
|
||||||
|
} else {
|
||||||
|
//并行
|
||||||
|
childrenQueue.forEach(childQueue -> {
|
||||||
|
this.executeCase(childQueue);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo @Chen jianxing 执行用例
|
||||||
|
private void executeCase(TestPlanExecutionQueue testPlanExecutionQueue) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//todo 测试用例执行完成中的某一条
|
||||||
|
private void TestCaseExecuteQueueFinish(String queueID, String queueType) {
|
||||||
|
/**
|
||||||
|
* 当队列全部执行完时,nextQueue将不会再查到。
|
||||||
|
* 此时如何调用父类队列的执行方式?
|
||||||
|
*/
|
||||||
|
TestPlanExecutionQueue nextQueue = getNextQueue(queueID, queueType);
|
||||||
if (nextQueue != null) {
|
if (nextQueue != null) {
|
||||||
try {
|
try {
|
||||||
executeTestPlan(testPlanMapper.selectByPrimaryKey(nextQueue.getTestPlanId()), nextQueue.getExecutionSource(), nextQueue.getCreateUser());
|
executeCase(nextQueue);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
this.executeNextTestPlanByQueueId(groupQueueId);
|
this.testPlanCollectionExecuteQueueFinish(nextQueue.getParentQueueId(), nextQueue.getParentQueueType());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// todo 测试计划组执行完成
|
// testPlanCollectionExecuteQueueFinish(queueID, queueType);
|
||||||
|
|
||||||
if (StringUtils.isNotEmpty(parentQueueId)) {
|
|
||||||
// 如果测试计划组是在批量执行时处理的,继续进行批量执行队列里的下个节点
|
|
||||||
executeNextTestPlanByQueueId(parentQueueId);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//执行下一个批量执行节点的测试计划
|
//todo 测试集执行完成中的某一条
|
||||||
private void executeNextTestPlanByQueueId(String queueId) {
|
private void testPlanCollectionExecuteQueueFinish(String queueID, String queueType) {
|
||||||
TestPlanExecutionQueue nextQueue = getNextDetail(queueId, QUEUE_PREFIX_TEST_PLAN, TestPlanExecutionQueue.class);
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//todo 测试计划执行完成中的某一条
|
||||||
|
private void TestPlanGroupExecuteQueueFinish(String queueID, String queueType) {
|
||||||
|
}
|
||||||
|
|
||||||
|
//测试计划批量执行队列节点执行完成
|
||||||
|
private void batchTestPlanExecuteQueueFinish(String queueId, String queueType) {
|
||||||
|
TestPlanExecutionQueue nextQueue = getNextQueue(queueId, queueType);
|
||||||
if (nextQueue != null) {
|
if (nextQueue != null) {
|
||||||
try {
|
try {
|
||||||
prepareExecuteTestPlan(
|
executeTestPlanOrGroup(nextQueue);
|
||||||
testPlanMapper.selectByPrimaryKey(nextQueue.getTestPlanId()),
|
|
||||||
queueId,
|
|
||||||
nextQueue.getRunMode(),
|
|
||||||
nextQueue.getExecutionSource(),
|
|
||||||
nextQueue.getCreateUser());
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
this.executeNextTestPlanByQueueId(queueId);
|
this.batchTestPlanExecuteQueueFinish(queueId, queueType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取下一个队列节点
|
* 获取下一个队列节点
|
||||||
*/
|
*/
|
||||||
private <T> T getNextDetail(String queueId, String queueType, Class<T> formatClass) {
|
private TestPlanExecutionQueue getNextQueue(String queueId, String queueType) {
|
||||||
String queueKey = this.genQueueKey(queueId, queueType);
|
String queueKey = this.genQueueKey(queueId, queueType);
|
||||||
ListOperations<String, String> listOps = redisTemplate.opsForList();
|
ListOperations<String, String> listOps = redisTemplate.opsForList();
|
||||||
String queueDetail = listOps.leftPop(queueKey);
|
String queueDetail = listOps.leftPop(queueKey);
|
||||||
|
@ -185,12 +325,14 @@ public class TestPlanExecuteService {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(queueDetail)) {
|
if (StringUtils.isNotBlank(queueDetail)) {
|
||||||
|
TestPlanExecutionQueue returnQueue = JSON.parseObject(queueDetail, TestPlanExecutionQueue.class);
|
||||||
Long size = getQueueSize(queueId);
|
Long size = getQueueSize(queueId);
|
||||||
if (size == null || size == 0) {
|
if (size == null || size == 0) {
|
||||||
|
returnQueue.setLastNode(true);
|
||||||
// 最后一个节点清理队列
|
// 最后一个节点清理队列
|
||||||
deleteQueue(queueKey);
|
deleteQueue(queueKey);
|
||||||
}
|
}
|
||||||
return JSON.parseObject(queueDetail, formatClass);
|
return returnQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 整体获取完,清理队列
|
// 整体获取完,清理队列
|
||||||
|
@ -209,14 +351,6 @@ public class TestPlanExecuteService {
|
||||||
|
|
||||||
//生成队列key
|
//生成队列key
|
||||||
private String genQueueKey(String queueId, String queueType) {
|
private String genQueueKey(String queueId, String queueType) {
|
||||||
String key = "";
|
return queueType + queueId;
|
||||||
if (StringUtils.equalsIgnoreCase(queueType, TestPlanExecuteQueueType.TEST_PLAN.name())) {
|
|
||||||
key = QUEUE_PREFIX_TEST_PLAN;
|
|
||||||
} else if (StringUtils.equalsIgnoreCase(queueType, TestPlanExecuteQueueType.TEST_PLAN_GROUP.name())) {
|
|
||||||
key = QUEUE_PREFIX_TEST_PLAN_GROUP;
|
|
||||||
} else if (StringUtils.equalsIgnoreCase(queueType, TestPlanExecuteQueueType.TEST_COLLECTION.name())) {
|
|
||||||
key = QUEUE_PREFIX_TEST_COLLECTION;
|
|
||||||
}
|
|
||||||
return key + queueId;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,9 @@ import io.metersphere.api.service.definition.ApiTestCaseService;
|
||||||
import io.metersphere.api.utils.ApiDataUtils;
|
import io.metersphere.api.utils.ApiDataUtils;
|
||||||
import io.metersphere.plan.constants.AssociateCaseType;
|
import io.metersphere.plan.constants.AssociateCaseType;
|
||||||
import io.metersphere.plan.domain.TestPlanApiCase;
|
import io.metersphere.plan.domain.TestPlanApiCase;
|
||||||
|
import io.metersphere.plan.domain.TestPlanApiCaseExample;
|
||||||
import io.metersphere.plan.dto.request.*;
|
import io.metersphere.plan.dto.request.*;
|
||||||
|
import io.metersphere.plan.dto.response.TestPlanOperationResponse;
|
||||||
import io.metersphere.plan.mapper.TestPlanApiCaseMapper;
|
import io.metersphere.plan.mapper.TestPlanApiCaseMapper;
|
||||||
import io.metersphere.plan.service.TestPlanApiCaseService;
|
import io.metersphere.plan.service.TestPlanApiCaseService;
|
||||||
import io.metersphere.project.mapper.ExtBaseProjectVersionMapper;
|
import io.metersphere.project.mapper.ExtBaseProjectVersionMapper;
|
||||||
|
@ -26,6 +28,7 @@ import io.metersphere.sdk.util.CommonBeanFactory;
|
||||||
import io.metersphere.sdk.util.JSON;
|
import io.metersphere.sdk.util.JSON;
|
||||||
import io.metersphere.system.base.BaseTest;
|
import io.metersphere.system.base.BaseTest;
|
||||||
import io.metersphere.system.controller.handler.ResultHolder;
|
import io.metersphere.system.controller.handler.ResultHolder;
|
||||||
|
import io.metersphere.system.dto.sdk.enums.MoveTypeEnum;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import org.junit.jupiter.api.*;
|
import org.junit.jupiter.api.*;
|
||||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||||
|
@ -51,6 +54,7 @@ public class TestPlanApiCaseControllerTests extends BaseTest {
|
||||||
public static final String API_CASE_DISASSOCIATE = "disassociate";
|
public static final String API_CASE_DISASSOCIATE = "disassociate";
|
||||||
public static final String API_CASE_BATCH_DISASSOCIATE = "batch/disassociate";
|
public static final String API_CASE_BATCH_DISASSOCIATE = "batch/disassociate";
|
||||||
public static final String API_CASE_BATCH_UPDATE_EXECUTOR_URL = "batch/update/executor";
|
public static final String API_CASE_BATCH_UPDATE_EXECUTOR_URL = "batch/update/executor";
|
||||||
|
private static final String URL_POST_RESOURCE_API_CASE_SORT = "/sort";
|
||||||
public static final String RUN = "run/{0}";
|
public static final String RUN = "run/{0}";
|
||||||
public static final String RUN_WITH_REPORT_ID = "run/{0}?reportId={1}";
|
public static final String RUN_WITH_REPORT_ID = "run/{0}?reportId={1}";
|
||||||
|
|
||||||
|
@ -109,6 +113,44 @@ public class TestPlanApiCaseControllerTests extends BaseTest {
|
||||||
|
|
||||||
request.setTreeType("COLLECTION");
|
request.setTreeType("COLLECTION");
|
||||||
this.requestPostWithOkAndReturn(API_CASE_TREE_COUNT, request);
|
this.requestPostWithOkAndReturn(API_CASE_TREE_COUNT, request);
|
||||||
|
|
||||||
|
this.testSort();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSort() throws Exception {
|
||||||
|
TestPlanApiCaseExample testPlanApiCaseExample = new TestPlanApiCaseExample();
|
||||||
|
testPlanApiCaseExample.createCriteria().andTestPlanCollectionIdEqualTo("wxxx_2");
|
||||||
|
testPlanApiCaseExample.setOrderByClause("pos asc");
|
||||||
|
List<TestPlanApiCase> apiList = testPlanApiCaseMapper.selectByExample(testPlanApiCaseExample);
|
||||||
|
|
||||||
|
//最后一个移动到第一位之前
|
||||||
|
ResourceSortRequest request = new ResourceSortRequest();
|
||||||
|
request.setTestCollectionId("wxxx_2");
|
||||||
|
request.setProjectId("wxx_1234");
|
||||||
|
request.setMoveId(apiList.getLast().getId());
|
||||||
|
request.setTargetId(apiList.getFirst().getId());
|
||||||
|
request.setMoveMode(MoveTypeEnum.AFTER.name());
|
||||||
|
|
||||||
|
MvcResult result = this.requestPostWithOkAndReturn(URL_POST_RESOURCE_API_CASE_SORT, request);
|
||||||
|
ResultHolder resultHolder = JSON.parseObject(result.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class);
|
||||||
|
TestPlanOperationResponse response = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), TestPlanOperationResponse.class);
|
||||||
|
Assertions.assertEquals(response.getOperationCount(), 1);
|
||||||
|
apiList = testPlanApiCaseMapper.selectByExample(testPlanApiCaseExample);
|
||||||
|
Assertions.assertEquals(apiList.get(0).getId(), request.getMoveId());
|
||||||
|
Assertions.assertEquals(apiList.get(1).getId(), request.getTargetId());
|
||||||
|
|
||||||
|
//将这时的第30个放到第一位之后
|
||||||
|
request.setTargetId(apiList.getLast().getId());
|
||||||
|
request.setMoveId(apiList.getFirst().getId());
|
||||||
|
request.setMoveMode(MoveTypeEnum.BEFORE.name());
|
||||||
|
result = this.requestPostWithOkAndReturn(URL_POST_RESOURCE_API_CASE_SORT, request);
|
||||||
|
resultHolder = JSON.parseObject(result.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class);
|
||||||
|
response = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), TestPlanOperationResponse.class);
|
||||||
|
Assertions.assertEquals(response.getOperationCount(), 1);
|
||||||
|
apiList = testPlanApiCaseMapper.selectByExample(testPlanApiCaseExample);
|
||||||
|
Assertions.assertEquals(apiList.get(0).getId(), request.getTargetId());
|
||||||
|
Assertions.assertEquals(apiList.get(1).getId(), request.getMoveId());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -30,9 +30,9 @@ VALUES
|
||||||
|
|
||||||
INSERT INTO `test_plan_api_case`(`id`, `test_plan_id`, `api_case_id`, `environment_id`, `last_exec_result`, `last_exec_report_id`, `execute_user`, `create_time`, `create_user`, `pos`, `test_plan_collection_id`, `last_exec_time`)
|
INSERT INTO `test_plan_api_case`(`id`, `test_plan_id`, `api_case_id`, `environment_id`, `last_exec_result`, `last_exec_report_id`, `execute_user`, `create_time`, `create_user`, `pos`, `test_plan_collection_id`, `last_exec_time`)
|
||||||
VALUES
|
VALUES
|
||||||
('wxxx_1', 'wxxx_1', 'wxxx_api_case_1', '1', NULL, NULL, 'admin', 1716370415311, 'admin', 2, 'wxxx_2', 1716370415311),
|
('wxxx_1', 'wxxx_1', 'wxxx_api_case_1', '1', NULL, NULL, 'admin', 1716370415311, 'admin', 4096, 'wxxx_2', 1716370415311),
|
||||||
('wxxx_2', 'wxxx_1', 'wxxx_api_case_2', '123', NULL, NULL, 'admin', 1716370415311, 'admin', 2, 'wxxx_3', 1716370415311),
|
('wxxx_2', 'wxxx_1', 'wxxx_api_case_2', '123', NULL, NULL, 'admin', 1716370415311, 'admin', 4096, 'wxxx_3', 1716370415311),
|
||||||
('wxxx_3', 'wxxx_2', 'wxxx_api_case_3', '1', NULL, NULL, 'admin', 1716370415311, 'admin', 2, 'wxxx_2', 1716370415311);
|
('wxxx_3', 'wxxx_2', 'wxxx_api_case_3', '1', NULL, NULL, 'admin', 1716370415311, 'admin', 8192, 'wxxx_2', 1716370415311);
|
||||||
|
|
||||||
INSERT INTO `test_plan_collection`(`id`, `test_plan_id`, `name`, `type`, `environment_id`, `test_resource_pool_id`, `pos`, `create_user`, `create_time`, `parent_id`)
|
INSERT INTO `test_plan_collection`(`id`, `test_plan_id`, `name`, `type`, `environment_id`, `test_resource_pool_id`, `pos`, `create_user`, `create_time`, `parent_id`)
|
||||||
VALUES
|
VALUES
|
||||||
|
|
Loading…
Reference in New Issue