feat(测试计划): 批量执行测试计划测试队列方法优化
This commit is contained in:
parent
8874a40b5b
commit
5d97da2a78
|
@ -31,5 +31,22 @@ public class TestPlanExecutionQueue {
|
|||
//预生成报告ID
|
||||
private String prepareReportId;
|
||||
|
||||
private boolean lastFinished = false;
|
||||
// 是否是队列的最后一个
|
||||
private boolean isLastOne = false;
|
||||
// 是否执行完毕
|
||||
private boolean executeFinish = false;
|
||||
|
||||
public TestPlanExecutionQueue(long pos, String createUser, long createTime, String queueId, String queueType, String parentQueueId, String parentQueueType, String sourceID, String runMode, String executionSource, String prepareReportId) {
|
||||
this.pos = pos;
|
||||
this.createUser = createUser;
|
||||
this.createTime = createTime;
|
||||
this.queueId = queueId;
|
||||
this.queueType = queueType;
|
||||
this.parentQueueId = parentQueueId;
|
||||
this.parentQueueType = parentQueueType;
|
||||
this.sourceID = sourceID;
|
||||
this.runMode = runMode;
|
||||
this.executionSource = executionSource;
|
||||
this.prepareReportId = prepareReportId;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,9 +49,6 @@ public class TestPlanCreateRequest {
|
|||
@Schema(description = "描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "是否开启测试规划", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private boolean testPlanning;
|
||||
|
||||
@Schema(description = "是否自定更新功能用例状态", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private boolean automaticStatusUpdate;
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@ import org.apache.commons.collections4.CollectionUtils;
|
|||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.data.redis.core.ListOperations;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
|
@ -44,12 +43,10 @@ public class TestPlanExecuteService {
|
|||
|
||||
@Resource
|
||||
private RedisTemplate<String, String> redisTemplate;
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
public static final String QUEUE_PREFIX_TEST_PLAN_GROUP = "test-plan-group-execute:";
|
||||
public static final String QUEUE_PREFIX_TEST_PLAN = "test-plan-execute:";
|
||||
public static final String QUEUE_PREFIX_TEST_PLAN_CASE_TYPE = "test-plan-case-type:";
|
||||
public static final String QUEUE_PREFIX_TEST_PLAN_BATCH_EXECUTE = "test-plan-batch-execute:";
|
||||
public static final String QUEUE_PREFIX_TEST_PLAN_GROUP_EXECUTE = "test-plan-group-execute:";
|
||||
public static final String QUEUE_PREFIX_TEST_PLAN_CASE_TYPE = "test-plan-case-type-execute:";
|
||||
public static final String QUEUE_PREFIX_TEST_PLAN_COLLECTION = "test-plan-collection-execute:";
|
||||
|
||||
public static final String LAST_QUEUE_PREFIX = "last-queue:";
|
||||
|
@ -73,7 +70,7 @@ public class TestPlanExecuteService {
|
|||
if (CollectionUtils.isNotEmpty(rightfulIds)) {
|
||||
String runMode = request.getRunMode();
|
||||
String queueId = IDGenerator.nextStr();
|
||||
String queueType = QUEUE_PREFIX_TEST_PLAN_GROUP;
|
||||
String queueType = QUEUE_PREFIX_TEST_PLAN_BATCH_EXECUTE;
|
||||
long pos = 0;
|
||||
List<TestPlanExecutionQueue> testPlanExecutionQueues = new ArrayList<>();
|
||||
|
||||
|
@ -92,7 +89,7 @@ public class TestPlanExecuteService {
|
|||
testPlanId,
|
||||
runMode,
|
||||
request.getExecutionSource(),
|
||||
IDGenerator.nextStr(), false
|
||||
IDGenerator.nextStr()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -124,7 +121,7 @@ public class TestPlanExecuteService {
|
|||
long pos = 0;
|
||||
List<TestPlanExecutionQueue> childrenQueue = new ArrayList<>();
|
||||
String queueId = IDGenerator.nextStr();
|
||||
String queueType = QUEUE_PREFIX_TEST_PLAN;
|
||||
String queueType = QUEUE_PREFIX_TEST_PLAN_GROUP_EXECUTE;
|
||||
for (TestPlan child : children) {
|
||||
childrenQueue.add(
|
||||
new TestPlanExecutionQueue(
|
||||
|
@ -138,23 +135,32 @@ public class TestPlanExecuteService {
|
|||
child.getId(),
|
||||
executionQueue.getRunMode(),
|
||||
executionQueue.getExecutionSource(),
|
||||
IDGenerator.nextStr(), false
|
||||
IDGenerator.nextStr()
|
||||
)
|
||||
);
|
||||
}
|
||||
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);
|
||||
executeTestPlanOrGroup(nextQueue);
|
||||
if (CollectionUtils.isEmpty(childrenQueue)) {
|
||||
//本次的测试计划组执行完成
|
||||
this.testPlanGroupQueueFinish(executionQueue.getQueueId(), executionQueue.getQueueType());
|
||||
} else {
|
||||
//并行
|
||||
childrenQueue.forEach(childQueue -> {
|
||||
executeTestPlanOrGroup(childQueue);
|
||||
redisTemplate.opsForList().rightPush(childQueue.getQueueType() + childQueue.getQueueId(), JSON.toJSONString(childQueue));
|
||||
});
|
||||
|
||||
// todo Song-cc 这里是否要生成测试计划组的集合报告,并且记录测试计划里用例的执行信息?
|
||||
|
||||
if (StringUtils.equalsIgnoreCase(executionQueue.getRunMode(), ApiBatchRunMode.SERIAL.name())) {
|
||||
//串行
|
||||
TestPlanExecutionQueue nextQueue = this.getNextQueue(queueId, queueType);
|
||||
executeTestPlanOrGroup(nextQueue);
|
||||
} else {
|
||||
//并行
|
||||
childrenQueue.forEach(childQueue -> {
|
||||
executeTestPlanOrGroup(childQueue);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return executionQueue.getPrepareReportId();
|
||||
} else {
|
||||
return this.executeTestPlan(executionQueue);
|
||||
|
@ -165,7 +171,7 @@ public class TestPlanExecuteService {
|
|||
public String executeTestPlan(TestPlanExecutionQueue executionQueue) {
|
||||
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(executionQueue.getSourceID());
|
||||
TestPlanCollectionExample testPlanCollectionExample = new TestPlanCollectionExample();
|
||||
testPlanCollectionExample.createCriteria().andTestPlanIdEqualTo(testPlan.getId());
|
||||
testPlanCollectionExample.createCriteria().andTestPlanIdEqualTo(testPlan.getId()).andParentIdEqualTo("NONE");
|
||||
testPlanCollectionExample.setOrderByClause("pos asc");
|
||||
//过滤掉功能用例的测试集
|
||||
List<TestPlanCollection> testPlanCollectionList = testPlanCollectionMapper.selectByExample(testPlanCollectionExample).stream().filter(
|
||||
|
@ -190,34 +196,41 @@ public class TestPlanExecuteService {
|
|||
executionQueue.getQueueId(),
|
||||
executionQueue.getQueueType(),
|
||||
collection.getId(),
|
||||
executionQueue.getRunMode(),
|
||||
runMode,
|
||||
executionQueue.getExecutionSource(),
|
||||
IDGenerator.nextStr(), false)
|
||||
IDGenerator.nextStr())
|
||||
);
|
||||
}
|
||||
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);
|
||||
if (CollectionUtils.isEmpty(childrenQueue)) {
|
||||
//本次的测试计划组执行完成
|
||||
this.testPlanExecuteQueueFinish(executionQueue.getQueueId(), executionQueue.getQueueType());
|
||||
} else {
|
||||
//并行
|
||||
childrenQueue.forEach(childQueue -> {
|
||||
this.executeByTestPlanCollection(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();
|
||||
}
|
||||
|
||||
//执行测试集 -- 回调:collectionExecuteQueueFinish
|
||||
private void executeByTestPlanCollection(TestPlanExecutionQueue executionQueue) {
|
||||
TestPlanCollection parentCollection = testPlanCollectionMapper.selectByPrimaryKey(executionQueue.getParentQueueId());
|
||||
TestPlanCollection parentCollection = testPlanCollectionMapper.selectByPrimaryKey(executionQueue.getSourceID());
|
||||
TestPlanCollectionExample example = new TestPlanCollectionExample();
|
||||
example.createCriteria().andParentIdEqualTo(executionQueue.getSourceID());
|
||||
List<TestPlanCollection> childrenList = testPlanCollectionMapper.selectByExample(example);
|
||||
|
@ -238,24 +251,30 @@ public class TestPlanExecuteService {
|
|||
executionQueue.getQueueId(),
|
||||
executionQueue.getQueueType(),
|
||||
collection.getId(),
|
||||
executionQueue.getRunMode(),
|
||||
collection.getExecuteMethod(),
|
||||
executionQueue.getExecutionSource(),
|
||||
IDGenerator.nextStr(), false)
|
||||
IDGenerator.nextStr())
|
||||
);
|
||||
}
|
||||
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);
|
||||
if (CollectionUtils.isEmpty(childrenQueue)) {
|
||||
//本次的测试集执行完成
|
||||
this.caseTypeExecuteQueueFinish(executionQueue.getQueueId(), executionQueue.getQueueType());
|
||||
} else {
|
||||
//并行
|
||||
childrenQueue.forEach(childQueue -> {
|
||||
this.executeCase(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 执行用例
|
||||
|
@ -277,8 +296,9 @@ public class TestPlanExecuteService {
|
|||
//测试集执行完成
|
||||
public void collectionExecuteQueueFinish(String queueID, String queueType) {
|
||||
TestPlanExecutionQueue nextQueue = getNextQueue(queueID, queueType);
|
||||
if (StringUtils.isNotBlank(nextQueue.getQueueId())) {
|
||||
if (!nextQueue.isLastFinished()) {
|
||||
if (StringUtils.equalsIgnoreCase(nextQueue.getRunMode(), ApiBatchRunMode.SERIAL.name())) {
|
||||
//串行时,由于是先拿出节点再判断执行,所以要判断节点的isExecuteFinish
|
||||
if (!nextQueue.isExecuteFinish()) {
|
||||
try {
|
||||
this.executeNextNode(nextQueue);
|
||||
} catch (Exception e) {
|
||||
|
@ -286,17 +306,20 @@ public class TestPlanExecuteService {
|
|||
}
|
||||
} else {
|
||||
//当前测试集执行完毕
|
||||
this.caseTypeExecuteQueueFinish(nextQueue.getParentQueueId(), nextQueue.getParentQueueType());
|
||||
this.queueExecuteFinish(nextQueue);
|
||||
}
|
||||
|
||||
} else if (nextQueue.isLastOne()) {
|
||||
//并行时,调用回调时意味着执行结束,所以判断是否是当前队列最后一个从而结束队列
|
||||
this.queueExecuteFinish(nextQueue);
|
||||
}
|
||||
}
|
||||
|
||||
//测试计划中当前用例类型的全部执行完成
|
||||
private void caseTypeExecuteQueueFinish(String queueID, String queueType) {
|
||||
TestPlanExecutionQueue nextQueue = getNextQueue(queueID, queueType);
|
||||
if (StringUtils.isNotBlank(nextQueue.getQueueId())) {
|
||||
if (!nextQueue.isLastFinished()) {
|
||||
if (StringUtils.equalsIgnoreCase(nextQueue.getRunMode(), ApiBatchRunMode.SERIAL.name())) {
|
||||
//串行时,由于是先拿出节点再判断执行,所以要判断节点的isExecuteFinish
|
||||
if (!nextQueue.isExecuteFinish()) {
|
||||
try {
|
||||
this.executeNextNode(nextQueue);
|
||||
} catch (Exception e) {
|
||||
|
@ -304,43 +327,58 @@ public class TestPlanExecuteService {
|
|||
}
|
||||
} else {
|
||||
//当前测试计划执行完毕
|
||||
this.testPlanExecuteQueueFinish(nextQueue.getParentQueueId(), nextQueue.getParentQueueType());
|
||||
this.queueExecuteFinish(nextQueue);
|
||||
}
|
||||
} else if (nextQueue.isLastOne()) {
|
||||
//并行时,调用回调时意味着执行结束,所以判断是否是当前队列最后一个从而结束队列
|
||||
this.queueExecuteFinish(nextQueue);
|
||||
}
|
||||
}
|
||||
|
||||
//测试计划执行完成
|
||||
private void testPlanExecuteQueueFinish(String queueID, String queueType) {
|
||||
TestPlanExecutionQueue nextQueue = getNextQueue(queueID, queueType);
|
||||
if (StringUtils.isNotBlank(nextQueue.getQueueId())) {
|
||||
if (!nextQueue.isLastFinished()) {
|
||||
if (StringUtils.equalsIgnoreCase(nextQueue.getRunMode(), ApiBatchRunMode.SERIAL.name())) {
|
||||
if (!nextQueue.isExecuteFinish()) {
|
||||
try {
|
||||
this.executeNextNode(nextQueue);
|
||||
} catch (Exception e) {
|
||||
this.testPlanExecuteQueueFinish(nextQueue.getQueueId(), nextQueue.getQueueType());
|
||||
}
|
||||
} else {
|
||||
this.testPlanGroupQueueFinish(nextQueue.getParentQueueId(), nextQueue.getParentQueueType());
|
||||
this.queueExecuteFinish(nextQueue);
|
||||
}
|
||||
} else if (nextQueue.isLastOne()) {
|
||||
//并行时,调用回调时意味着执行结束,所以判断是否是当前队列最后一个从而结束队列
|
||||
this.queueExecuteFinish(nextQueue);
|
||||
}
|
||||
}
|
||||
|
||||
//测试计划批量执行队列节点执行完成
|
||||
private void testPlanGroupQueueFinish(String queueId, String queueType) {
|
||||
TestPlanExecutionQueue nextQueue = getNextQueue(queueId, queueType);
|
||||
if (nextQueue != null) {
|
||||
try {
|
||||
this.executeNextNode(nextQueue);
|
||||
} catch (Exception e) {
|
||||
this.testPlanGroupQueueFinish(queueId, queueType);
|
||||
}
|
||||
private void testPlanGroupQueueFinish(String queueID, String queueType) {
|
||||
TestPlanExecutionQueue nextQueue = getNextQueue(queueID, queueType);
|
||||
if (nextQueue == null) {
|
||||
return;
|
||||
}
|
||||
if (StringUtils.equalsIgnoreCase(nextQueue.getRunMode(), ApiBatchRunMode.SERIAL.name())) {
|
||||
if (!nextQueue.isExecuteFinish()) {
|
||||
try {
|
||||
this.executeNextNode(nextQueue);
|
||||
} catch (Exception e) {
|
||||
this.testPlanGroupQueueFinish(queueID, queueType);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//并行时,调用回调时意味着执行结束,所以判断是否是当前队列最后一个从而结束队列
|
||||
this.queueExecuteFinish(nextQueue);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void executeNextNode(TestPlanExecutionQueue queue) {
|
||||
if (StringUtils.equalsIgnoreCase(queue.getQueueType(), QUEUE_PREFIX_TEST_PLAN_GROUP)) {
|
||||
if (StringUtils.equalsIgnoreCase(queue.getQueueType(), QUEUE_PREFIX_TEST_PLAN_BATCH_EXECUTE)) {
|
||||
this.executeTestPlanOrGroup(queue);
|
||||
} else if (StringUtils.equalsIgnoreCase(queue.getQueueType(), QUEUE_PREFIX_TEST_PLAN)) {
|
||||
} else if (StringUtils.equalsIgnoreCase(queue.getQueueType(), QUEUE_PREFIX_TEST_PLAN_GROUP_EXECUTE)) {
|
||||
this.executeTestPlan(queue);
|
||||
} else if (StringUtils.equalsIgnoreCase(queue.getQueueType(), QUEUE_PREFIX_TEST_PLAN_CASE_TYPE)) {
|
||||
this.executeByTestPlanCollection(queue);
|
||||
|
@ -350,9 +388,11 @@ public class TestPlanExecuteService {
|
|||
}
|
||||
|
||||
private void queueExecuteFinish(TestPlanExecutionQueue queue) {
|
||||
if (StringUtils.equalsIgnoreCase(queue.getParentQueueType(), QUEUE_PREFIX_TEST_PLAN_GROUP)) {
|
||||
if (StringUtils.equalsIgnoreCase(queue.getParentQueueType(), QUEUE_PREFIX_TEST_PLAN_BATCH_EXECUTE)) {
|
||||
// todo Song-cc 测试计划组集合报告生成
|
||||
this.testPlanGroupQueueFinish(queue.getParentQueueId(), queue.getParentQueueType());
|
||||
} else if (StringUtils.equalsIgnoreCase(queue.getParentQueueType(), QUEUE_PREFIX_TEST_PLAN)) {
|
||||
} else if (StringUtils.equalsIgnoreCase(queue.getParentQueueType(), QUEUE_PREFIX_TEST_PLAN_GROUP_EXECUTE)) {
|
||||
// todo Song-cc 测试计划报告计算
|
||||
this.testPlanExecuteQueueFinish(queue.getParentQueueId(), queue.getParentQueueType());
|
||||
} else if (StringUtils.equalsIgnoreCase(queue.getParentQueueType(), QUEUE_PREFIX_TEST_PLAN_CASE_TYPE)) {
|
||||
this.caseTypeExecuteQueueFinish(queue.getParentQueueId(), queue.getParentQueueType());
|
||||
|
@ -369,10 +409,9 @@ public class TestPlanExecuteService {
|
|||
|
||||
String queueKey = this.genQueueKey(queueId, queueType);
|
||||
ListOperations<String, String> listOps = redisTemplate.opsForList();
|
||||
|
||||
String queueDetail = listOps.leftPop(queueKey);
|
||||
if (StringUtils.isBlank(queueDetail)) {
|
||||
// 重试3次获取
|
||||
// 重试2次获取
|
||||
for (int i = 0; i < 3; i++) {
|
||||
queueDetail = redisTemplate.opsForList().leftPop(queueKey);
|
||||
if (StringUtils.isNotBlank(queueDetail)) {
|
||||
|
@ -387,18 +426,22 @@ public class TestPlanExecuteService {
|
|||
|
||||
if (StringUtils.isNotBlank(queueDetail)) {
|
||||
TestPlanExecutionQueue returnQueue = JSON.parseObject(queueDetail, TestPlanExecutionQueue.class);
|
||||
Long size = getQueueSize(queueId);
|
||||
Long size = listOps.size(queueKey);
|
||||
if (size == null || size == 0) {
|
||||
returnQueue.setLastOne(true);
|
||||
if (StringUtils.equalsIgnoreCase(returnQueue.getRunMode(), ApiBatchRunMode.SERIAL.name())) {
|
||||
//串行的执行方式意味着最后一个节点要单独存储
|
||||
redisTemplate.opsForValue().setIfAbsent(genQueueKey(queueKey, LAST_QUEUE_PREFIX), JSON.toJSONString(returnQueue), 1, TimeUnit.DAYS);
|
||||
}
|
||||
// 最后一个节点清理队列
|
||||
deleteQueue(queueKey);
|
||||
redisTemplate.opsForValue().setIfAbsent(genQueueKey(LAST_QUEUE_PREFIX, queueKey), JSON.toJSONString(returnQueue), 1, TimeUnit.DAYS);
|
||||
}
|
||||
return returnQueue;
|
||||
} else {
|
||||
String lastQueueJson = redisTemplate.opsForValue().getAndDelete(genQueueKey(LAST_QUEUE_PREFIX, queueKey));
|
||||
String lastQueueJson = redisTemplate.opsForValue().getAndDelete(genQueueKey(queueKey, LAST_QUEUE_PREFIX));
|
||||
if (StringUtils.isNotBlank(lastQueueJson)) {
|
||||
TestPlanExecutionQueue nextQueue = JSON.parseObject(lastQueueJson, TestPlanExecutionQueue.class);
|
||||
nextQueue.setLastFinished(true);
|
||||
nextQueue.setExecuteFinish(true);
|
||||
return nextQueue;
|
||||
}
|
||||
}
|
||||
|
@ -413,11 +456,6 @@ public class TestPlanExecuteService {
|
|||
redisTemplate.delete(queueKey);
|
||||
}
|
||||
|
||||
private Long getQueueSize(String queueKey) {
|
||||
ListOperations<String, String> listOps = redisTemplate.opsForList();
|
||||
return listOps.size(queueKey);
|
||||
}
|
||||
|
||||
//生成队列key
|
||||
private String genQueueKey(String queueId, String queueType) {
|
||||
return queueType + queueId;
|
||||
|
|
|
@ -105,6 +105,8 @@ public class TestPlanService extends TestPlanBaseUtilsService {
|
|||
*/
|
||||
public TestPlan add(TestPlanCreateRequest testPlanCreateRequest, String operator, String requestUrl, String requestMethod) {
|
||||
TestPlan testPlan = savePlanDTO(testPlanCreateRequest, operator);
|
||||
//自动生成测试规划
|
||||
this.initDefaultPlanCollection(testPlan.getId(), operator);
|
||||
testPlanLogService.saveAddLog(testPlan, operator, requestUrl, requestMethod);
|
||||
return testPlan;
|
||||
}
|
||||
|
@ -139,7 +141,8 @@ public class TestPlanService extends TestPlanBaseUtilsService {
|
|||
testPlanConfig.setRepeatCase(createOrCopyRequest.isRepeatCase());
|
||||
testPlanConfig.setPassThreshold(createOrCopyRequest.getPassThreshold());
|
||||
|
||||
handleAssociateCase(createOrCopyRequest.getBaseAssociateCaseRequest(), operator, createTestPlan);
|
||||
//正式版本不再支持这种操作
|
||||
// handleAssociateCase(createOrCopyRequest.getBaseAssociateCaseRequest(), operator, createTestPlan);
|
||||
|
||||
testPlanMapper.insert(createTestPlan);
|
||||
testPlanConfigMapper.insertSelective(testPlanConfig);
|
||||
|
|
|
@ -0,0 +1,293 @@
|
|||
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.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.service.TestPlanExecuteService;
|
||||
import io.metersphere.plan.service.TestPlanTestService;
|
||||
import io.metersphere.project.domain.Project;
|
||||
import io.metersphere.sdk.constants.ApiBatchRunMode;
|
||||
import io.metersphere.sdk.constants.ModuleConstants;
|
||||
import io.metersphere.sdk.constants.TestPlanConstants;
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
import io.metersphere.system.base.BaseTest;
|
||||
import io.metersphere.system.controller.handler.ResultHolder;
|
||||
import io.metersphere.system.dto.AddProjectRequest;
|
||||
import io.metersphere.system.log.constants.OperationLogModule;
|
||||
import io.metersphere.system.service.CommonProjectService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.junit.jupiter.api.*;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
@AutoConfigureMockMvc
|
||||
public class TestPlanExecuteTests extends BaseTest {
|
||||
private static Project project;
|
||||
private static List<TestPlan> testPlanGroupList = new ArrayList<>();
|
||||
private static TestPlan allSerialGroup;
|
||||
private static TestPlan allParallelGroup;
|
||||
private static TestPlan noGroupPlan;
|
||||
|
||||
private static final String URL_POST_TEST_PLAN_SINGLE_EXECUTE = "/test-plan-execute/single";
|
||||
private static final String URL_POST_TEST_PLAN_BATCH_EXECUTE = "/test-plan-execute/batch";
|
||||
|
||||
@Resource
|
||||
private CommonProjectService commonProjectService;
|
||||
@Resource
|
||||
private TestPlanMapper testPlanMapper;
|
||||
@Resource
|
||||
private TestPlanTestService testPlanTestService;
|
||||
@Resource
|
||||
private TestPlanExecuteService testPlanExecuteService;
|
||||
@Resource
|
||||
private TestPlanConfigMapper testPlanConfigMapper;
|
||||
@Resource
|
||||
private TestPlanCollectionMapper testPlanCollectionMapper;
|
||||
|
||||
public static final String[] EXECUTE_QUEUE_PREFIX = new String[]{
|
||||
"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:";
|
||||
|
||||
@Test
|
||||
@Order(1)
|
||||
public void initData() throws Exception {
|
||||
AddProjectRequest initProject = new AddProjectRequest();
|
||||
initProject.setOrganizationId("100001");
|
||||
initProject.setName("测试计划执行专用项目");
|
||||
initProject.setDescription("建国创建的测试计划执行专用项目");
|
||||
initProject.setEnable(true);
|
||||
initProject.setUserIds(List.of("admin"));
|
||||
project = commonProjectService.add(initProject, "admin", "/organization-project/add", OperationLogModule.SETTING_ORGANIZATION_PROJECT);
|
||||
testPlanTestService.resetProjectModule(project, new String[]{"workstation", "testPlan", "bugManagement", "caseManagement", "apiTest", "uiTest", "loadTest"});
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
TestPlanCreateRequest request = new TestPlanCreateRequest();
|
||||
request.setProjectId(project.getId());
|
||||
request.setType(TestPlanConstants.TEST_PLAN_TYPE_GROUP);
|
||||
request.setName("testPlanGroupForExecute:" + i);
|
||||
request.setModuleId(ModuleConstants.DEFAULT_NODE_ID);
|
||||
MvcResult mvcResult = this.requestPostWithOkAndReturn("/test-plan/add", request);
|
||||
String returnStr = mvcResult.getResponse().getContentAsString();
|
||||
ResultHolder holder = JSON.parseObject(returnStr, ResultHolder.class);
|
||||
String returnId = JSON.parseObject(JSON.toJSONString(holder.getData()), TestPlan.class).getId();
|
||||
testPlanGroupList.add(testPlanMapper.selectByPrimaryKey(returnId));
|
||||
|
||||
if (i == 0) {
|
||||
allSerialGroup = testPlanMapper.selectByPrimaryKey(returnId);
|
||||
//第一个全部都是串行
|
||||
request = new TestPlanCreateRequest();
|
||||
request.setProjectId(project.getId());
|
||||
request.setType(TestPlanConstants.TEST_PLAN_TYPE_PLAN);
|
||||
request.setName("testPlanForExecute:" + i);
|
||||
request.setModuleId(ModuleConstants.DEFAULT_NODE_ID);
|
||||
request.setGroupId(returnId);
|
||||
mvcResult = this.requestPostWithOkAndReturn("/test-plan/add", request);
|
||||
returnStr = mvcResult.getResponse().getContentAsString();
|
||||
holder = JSON.parseObject(returnStr, ResultHolder.class);
|
||||
returnId = JSON.parseObject(JSON.toJSONString(holder.getData()), TestPlan.class).getId();
|
||||
|
||||
TestPlanConfig testPlanConfig = new TestPlanConfig();
|
||||
testPlanConfig.setTestPlanId(returnId);
|
||||
testPlanConfig.setCaseRunMode(ApiBatchRunMode.SERIAL.name());
|
||||
testPlanConfigMapper.updateByPrimaryKeySelective(testPlanConfig);
|
||||
|
||||
TestPlanCollectionExample testPlanCollectionExample = new TestPlanCollectionExample();
|
||||
testPlanCollectionExample.createCriteria().andTestPlanIdEqualTo(returnId);
|
||||
List<TestPlanCollection> testPlanCollections = testPlanCollectionMapper.selectByExample(testPlanCollectionExample);
|
||||
testPlanCollections.forEach(item -> {
|
||||
item.setExecuteMethod(ApiBatchRunMode.SERIAL.name());
|
||||
testPlanCollectionMapper.updateByPrimaryKeySelective(item);
|
||||
});
|
||||
|
||||
} else if (i == 1) {
|
||||
allParallelGroup = testPlanMapper.selectByPrimaryKey(returnId);
|
||||
|
||||
//第二个全部都是并行
|
||||
request = new TestPlanCreateRequest();
|
||||
request.setProjectId(project.getId());
|
||||
request.setType(TestPlanConstants.TEST_PLAN_TYPE_PLAN);
|
||||
request.setName("testPlanForExecute:" + i);
|
||||
request.setModuleId(ModuleConstants.DEFAULT_NODE_ID);
|
||||
request.setGroupId(returnId);
|
||||
mvcResult = this.requestPostWithOkAndReturn("/test-plan/add", request);
|
||||
returnStr = mvcResult.getResponse().getContentAsString();
|
||||
holder = JSON.parseObject(returnStr, ResultHolder.class);
|
||||
returnId = JSON.parseObject(JSON.toJSONString(holder.getData()), TestPlan.class).getId();
|
||||
|
||||
|
||||
TestPlanConfig testPlanConfig = new TestPlanConfig();
|
||||
testPlanConfig.setTestPlanId(returnId);
|
||||
testPlanConfig.setCaseRunMode(ApiBatchRunMode.PARALLEL.name());
|
||||
testPlanConfigMapper.updateByPrimaryKeySelective(testPlanConfig);
|
||||
|
||||
TestPlanCollectionExample testPlanCollectionExample = new TestPlanCollectionExample();
|
||||
testPlanCollectionExample.createCriteria().andTestPlanIdEqualTo(returnId);
|
||||
List<TestPlanCollection> testPlanCollections = testPlanCollectionMapper.selectByExample(testPlanCollectionExample);
|
||||
testPlanCollections.forEach(item -> {
|
||||
item.setExecuteMethod(ApiBatchRunMode.PARALLEL.name());
|
||||
testPlanCollectionMapper.updateByPrimaryKeySelective(item);
|
||||
});
|
||||
} else if (i == 2) {
|
||||
// 第三个走默认方法
|
||||
request = new TestPlanCreateRequest();
|
||||
request.setProjectId(project.getId());
|
||||
request.setType(TestPlanConstants.TEST_PLAN_TYPE_PLAN);
|
||||
request.setName("testPlanForExecute:" + i);
|
||||
request.setModuleId(ModuleConstants.DEFAULT_NODE_ID);
|
||||
request.setGroupId(returnId);
|
||||
mvcResult = this.requestPostWithOkAndReturn("/test-plan/add", request);
|
||||
returnStr = mvcResult.getResponse().getContentAsString();
|
||||
holder = JSON.parseObject(returnStr, ResultHolder.class);
|
||||
returnId = JSON.parseObject(JSON.toJSONString(holder.getData()), TestPlan.class).getId();
|
||||
}
|
||||
}
|
||||
|
||||
TestPlanCreateRequest request = new TestPlanCreateRequest();
|
||||
request.setProjectId(project.getId());
|
||||
request.setType(TestPlanConstants.TEST_PLAN_TYPE_PLAN);
|
||||
request.setName("testPlanForSingleExecute");
|
||||
request.setModuleId(ModuleConstants.DEFAULT_NODE_ID);
|
||||
MvcResult mvcResult = this.requestPostWithOkAndReturn("/test-plan/add", request);
|
||||
String returnStr = mvcResult.getResponse().getContentAsString();
|
||||
ResultHolder holder = JSON.parseObject(returnStr, ResultHolder.class);
|
||||
String returnId = JSON.parseObject(JSON.toJSONString(holder.getData()), TestPlan.class).getId();
|
||||
noGroupPlan = testPlanMapper.selectByPrimaryKey(returnId);
|
||||
}
|
||||
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
@Test
|
||||
@Order(2)
|
||||
public void executeTest() throws Exception {
|
||||
if (CollectionUtils.isEmpty(testPlanGroupList)) {
|
||||
this.initData();
|
||||
}
|
||||
|
||||
List<String> batchExecuteIds = new ArrayList<>();
|
||||
batchExecuteIds.add(noGroupPlan.getId());
|
||||
for (TestPlan group : testPlanGroupList) {
|
||||
batchExecuteIds.add(group.getId());
|
||||
}
|
||||
|
||||
// 串行4个计划组和一个计划
|
||||
this.executeBatch(batchExecuteIds, ApiBatchRunMode.SERIAL.name());
|
||||
//并行4个计划组和一个计划
|
||||
this.executeBatch(batchExecuteIds, ApiBatchRunMode.PARALLEL.name());
|
||||
|
||||
|
||||
//单独串行一个计划组
|
||||
this.executeOne(allSerialGroup.getId(), ApiBatchRunMode.SERIAL.name());
|
||||
//单独串行一个计划
|
||||
this.executeOne(noGroupPlan.getId(), ApiBatchRunMode.SERIAL.name());
|
||||
|
||||
//单独并行一个计划组
|
||||
this.executeOne(allParallelGroup.getId(), ApiBatchRunMode.PARALLEL.name());
|
||||
//单独并行一个计划
|
||||
this.executeOne(noGroupPlan.getId(), ApiBatchRunMode.PARALLEL.name());
|
||||
}
|
||||
|
||||
private void executeBatch(List<String> execIds, String runMode) throws Exception {
|
||||
|
||||
TestPlanBatchExecuteRequest batchExecuteRequest = new TestPlanBatchExecuteRequest();
|
||||
batchExecuteRequest.setExecuteIds(execIds);
|
||||
batchExecuteRequest.setProjectId(project.getId());
|
||||
batchExecuteRequest.setRunMode(runMode);
|
||||
|
||||
this.requestPostWithOk(URL_POST_TEST_PLAN_BATCH_EXECUTE, batchExecuteRequest);
|
||||
|
||||
//检查队列
|
||||
List<String> allQueueIds = new ArrayList<>();
|
||||
List<String> collectionQueueIdList = new ArrayList<>();
|
||||
for (String executeQueue : EXECUTE_QUEUE_PREFIX) {
|
||||
Set<String> keys = stringRedisTemplate.keys("*" + executeQueue + "*");
|
||||
allQueueIds.addAll(keys);
|
||||
for (String key : keys) {
|
||||
if (StringUtils.equalsIgnoreCase(executeQueue, QUEUE_PREFIX_TEST_PLAN_COLLECTION)) {
|
||||
String[] keyArr = key.split(QUEUE_PREFIX_TEST_PLAN_COLLECTION);
|
||||
collectionQueueIdList.add(keyArr[keyArr.length - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Assertions.assertTrue(!collectionQueueIdList.isEmpty());
|
||||
Assertions.assertTrue(!allQueueIds.isEmpty());
|
||||
|
||||
this.checkRedisKeyEmpty(allQueueIds, collectionQueueIdList);
|
||||
|
||||
}
|
||||
|
||||
private void executeOne(String id, String runMode) throws Exception {
|
||||
TestPlanExecuteRequest executeRequest = new TestPlanExecuteRequest();
|
||||
executeRequest.setExecuteId(id);
|
||||
executeRequest.setRunMode(runMode);
|
||||
|
||||
this.requestPostWithOk(URL_POST_TEST_PLAN_SINGLE_EXECUTE, executeRequest);
|
||||
|
||||
//检查队列
|
||||
List<String> allQueueIds = new ArrayList<>();
|
||||
List<String> collectionQueueIdList = new ArrayList<>();
|
||||
for (String executeQueue : EXECUTE_QUEUE_PREFIX) {
|
||||
Set<String> keys = stringRedisTemplate.keys("*" + executeQueue + "*");
|
||||
allQueueIds.addAll(keys);
|
||||
for (String key : keys) {
|
||||
if (StringUtils.equalsIgnoreCase(executeQueue, QUEUE_PREFIX_TEST_PLAN_COLLECTION)) {
|
||||
String[] keyArr = key.split(QUEUE_PREFIX_TEST_PLAN_COLLECTION);
|
||||
collectionQueueIdList.add(keyArr[keyArr.length - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Assertions.assertTrue(!collectionQueueIdList.isEmpty());
|
||||
Assertions.assertTrue(!allQueueIds.isEmpty());
|
||||
|
||||
this.checkRedisKeyEmpty(allQueueIds, collectionQueueIdList);
|
||||
|
||||
}
|
||||
|
||||
private void checkRedisKeyEmpty(List<String> allQueueIds, List<String> collectionQueueIdList) throws Exception {
|
||||
//本条测试用例中,最多传入的是5个批量执行。(4个测试计划组和1个测试计划, 有一个测试计划组下面没有测试计划),
|
||||
// 串行的话模拟其中8个测试集的回调。 既while中最多循环8次进行回调,每次回调只传入1个测试集,防止并行/串行的干扰
|
||||
int foreachIndex = 8;
|
||||
long timeStem = System.currentTimeMillis();
|
||||
while (foreachIndex > 0 && !allQueueIds.isEmpty()) {
|
||||
|
||||
String collectionFinishQueueIds = collectionQueueIdList.getFirst();
|
||||
//模拟执行完成之后的回调
|
||||
testPlanExecuteService.collectionExecuteQueueFinish(collectionFinishQueueIds, QUEUE_PREFIX_TEST_PLAN_COLLECTION);
|
||||
|
||||
allQueueIds = new ArrayList<>();
|
||||
collectionQueueIdList = new ArrayList<>();
|
||||
|
||||
for (String executeQueue : EXECUTE_QUEUE_PREFIX) {
|
||||
Set<String> keys = stringRedisTemplate.keys("*" + executeQueue + "*");
|
||||
allQueueIds.addAll(keys);
|
||||
for (String key : keys) {
|
||||
if (StringUtils.equalsIgnoreCase(executeQueue, QUEUE_PREFIX_TEST_PLAN_COLLECTION)) {
|
||||
String[] keyArr = key.split(QUEUE_PREFIX_TEST_PLAN_COLLECTION);
|
||||
collectionQueueIdList.add(keyArr[keyArr.length - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreachIndex--;
|
||||
}
|
||||
|
||||
Assertions.assertTrue(allQueueIds.isEmpty());
|
||||
}
|
||||
}
|
|
@ -119,8 +119,6 @@ public class TestPlanTests extends BaseTest {
|
|||
private static final String URL_POST_TEST_PLAN_BATCH_DELETE = "/test-plan/batch-delete";
|
||||
private static final String URL_POST_TEST_PLAN_SCHEDULE = "/test-plan/schedule-config";
|
||||
private static final String URL_POST_TEST_PLAN_SCHEDULE_DELETE = "/test-plan/schedule-config-delete/%s";
|
||||
private static final String URL_POST_TEST_PLAN_SINGLE_EXECUTE = "/test-plan-execute/single";
|
||||
private static final String URL_POST_TEST_PLAN_BATCH_EXECUTE = "/test-plan-execute/batch";
|
||||
|
||||
//测试计划资源-功能用例
|
||||
private static final String URL_POST_RESOURCE_CASE_ASSOCIATION = "/test-plan/association";
|
||||
|
@ -531,7 +529,6 @@ public class TestPlanTests extends BaseTest {
|
|||
assert a1Node != null & a2Node != null & a3Node != null & a1a1Node != null & a1b1Node != null;
|
||||
TestPlanCreateRequest request = new TestPlanCreateRequest();
|
||||
request.setProjectId(project.getId());
|
||||
request.setTestPlanning(false);
|
||||
|
||||
BaseAssociateCaseRequest associateCaseRequest = new BaseAssociateCaseRequest();
|
||||
request.setBaseAssociateCaseRequest(associateCaseRequest);
|
||||
|
@ -1482,26 +1479,6 @@ public class TestPlanTests extends BaseTest {
|
|||
Assertions.assertTrue(statisticsResponses.getFirst().getScheduleConfig() == null);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(71)
|
||||
public void executeTest() throws Exception {
|
||||
TestPlanExecuteRequest executeRequest = new TestPlanExecuteRequest();
|
||||
executeRequest.setExecuteId(groupTestPlanId7);
|
||||
//串行
|
||||
this.requestPostWithOk(URL_POST_TEST_PLAN_SINGLE_EXECUTE, executeRequest);
|
||||
//并行
|
||||
executeRequest.setRunMode(ApiBatchRunMode.PARALLEL.name());
|
||||
this.requestPostWithOk(URL_POST_TEST_PLAN_SINGLE_EXECUTE, executeRequest);
|
||||
|
||||
TestPlanBatchExecuteRequest batchExecuteRequest = new TestPlanBatchExecuteRequest();
|
||||
batchExecuteRequest.setExecuteIds(Collections.singletonList(groupTestPlanId7));
|
||||
batchExecuteRequest.setProjectId(project.getId());
|
||||
//串行
|
||||
this.requestPostWithOk(URL_POST_TEST_PLAN_BATCH_EXECUTE, batchExecuteRequest);
|
||||
//并行
|
||||
batchExecuteRequest.setRunMode(ApiBatchRunMode.PARALLEL.name());
|
||||
this.requestPostWithOk(URL_POST_TEST_PLAN_BATCH_EXECUTE, batchExecuteRequest);
|
||||
}
|
||||
@Test
|
||||
@Order(81)
|
||||
public void copyTestPlan() throws Exception {
|
||||
|
@ -2139,7 +2116,6 @@ public class TestPlanTests extends BaseTest {
|
|||
public void testAdd() throws Exception {
|
||||
TestPlanCreateRequest request = new TestPlanCreateRequest();
|
||||
request.setProjectId(project.getId());
|
||||
request.setTestPlanning(false);
|
||||
BaseAssociateCaseRequest associateCaseRequest = new BaseAssociateCaseRequest();
|
||||
associateCaseRequest.setFunctionalSelectIds(Arrays.asList("wx_fc_1", "wx_fc_2"));
|
||||
request.setBaseAssociateCaseRequest(associateCaseRequest);
|
||||
|
|
Loading…
Reference in New Issue