feat(测试计划): 批量执行测试计划测试队列方法优化

This commit is contained in:
Jianguo-Genius 2024-06-12 17:24:27 +08:00 committed by 刘瑞斌
parent 8874a40b5b
commit 5d97da2a78
6 changed files with 432 additions and 108 deletions

View File

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

View File

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

View File

@ -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,13 +135,20 @@ public class TestPlanExecuteService {
child.getId(),
executionQueue.getRunMode(),
executionQueue.getExecutionSource(),
IDGenerator.nextStr(), false
IDGenerator.nextStr()
)
);
}
if (CollectionUtils.isEmpty(childrenQueue)) {
//本次的测试计划组执行完成
this.testPlanGroupQueueFinish(executionQueue.getQueueId(), executionQueue.getQueueType());
} else {
childrenQueue.forEach(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);
@ -155,6 +159,8 @@ public class TestPlanExecuteService {
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,11 +196,16 @@ public class TestPlanExecuteService {
executionQueue.getQueueId(),
executionQueue.getQueueType(),
collection.getId(),
executionQueue.getRunMode(),
runMode,
executionQueue.getExecutionSource(),
IDGenerator.nextStr(), false)
IDGenerator.nextStr())
);
}
if (CollectionUtils.isEmpty(childrenQueue)) {
//本次的测试计划组执行完成
this.testPlanExecuteQueueFinish(executionQueue.getQueueId(), executionQueue.getQueueType());
} else {
childrenQueue.forEach(childQueue -> {
redisTemplate.opsForList().rightPush(childQueue.getQueueType() + childQueue.getQueueId(), JSON.toJSONString(childQueue));
});
@ -212,12 +223,14 @@ public class TestPlanExecuteService {
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,11 +251,15 @@ public class TestPlanExecuteService {
executionQueue.getQueueId(),
executionQueue.getQueueType(),
collection.getId(),
executionQueue.getRunMode(),
collection.getExecuteMethod(),
executionQueue.getExecutionSource(),
IDGenerator.nextStr(), false)
IDGenerator.nextStr())
);
}
if (CollectionUtils.isEmpty(childrenQueue)) {
//本次的测试集执行完成
this.caseTypeExecuteQueueFinish(executionQueue.getQueueId(), executionQueue.getQueueType());
} else {
childrenQueue.forEach(childQueue -> {
redisTemplate.opsForList().rightPush(childQueue.getQueueType() + childQueue.getQueueId(), JSON.toJSONString(childQueue));
});
@ -258,6 +275,8 @@ public class TestPlanExecuteService {
}
}
}
// todo @Chen jianxing 执行用例
private void executeCase(TestPlanExecutionQueue testPlanExecutionQueue) {
String queueId = testPlanExecutionQueue.getQueueId();
@ -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) {
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);
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;

View File

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

View File

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

View File

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