feat(接口测试): 任务中心-接口执行改造

--task=1016475 --user=陈建星 批量执行优化 https://www.tapd.cn/55049933/s/1589205
This commit is contained in:
AgAngle 2024-10-14 16:21:08 +08:00 committed by Craftsman
parent 0fa54338dd
commit cfa6bee542
54 changed files with 1348 additions and 461 deletions

View File

@ -11,6 +11,13 @@ import java.util.Map;
*/
@Data
public abstract class ParameterConfig {
/**
* 任务项的唯一ID
*/
private String taskItemId;
/**
* 报告ID
*/
private String reportId;
/**
* 解析时是否解析 enable false 的组件

View File

@ -1,5 +1,7 @@
package io.metersphere.sdk.constants;
import org.apache.commons.lang3.StringUtils;
/**
* 接口执行时的资源类型
*
@ -27,5 +29,13 @@ public enum ApiExecuteRunMode {
/**
* 定时任务
*/
SCHEDULE
SCHEDULE;
public static boolean isDebug(String runMode) {
return StringUtils.equalsAny(runMode, ApiExecuteRunMode.FRONTEND_DEBUG.name(), ApiExecuteRunMode.BACKEND_DEBUG.name());
}
public static boolean isFrontendDebug(String runMode) {
return StringUtils.equals(runMode, ApiExecuteRunMode.FRONTEND_DEBUG.name());
}
}

View File

@ -38,4 +38,14 @@ public class GetRunScriptRequest implements Serializable {
* @see io.metersphere.sdk.constants.ApiExecuteResourceType
*/
private String resourceType;
/**
* 是否需要解析脚本
* 接口详情页面需要传试试详情会其他解析脚本needParseScript false
* 不传详情执行时通过 task-runner 发起解析脚本请求needParseScript true
*/
private Boolean needParseScript = false;
/**
* 线程ID
*/
private String threadId;
}

View File

@ -16,9 +16,21 @@ import java.util.List;
public class TaskInfo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 任务ID
*/
private String taskId;
private String msUrl;
private String kafkaConfig;
private String minioConfig;
/**
* 单个任务的并发数
*/
private int perTaskSize;
/**
* 资源池的并发数
*/
private int poolSize;
/**
* 批量执行时的队列ID

View File

@ -14,6 +14,12 @@ public class TaskItem implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 任务项ID
*/
@NotBlank
private String id;
@NotBlank
private String reportId;
/**

View File

@ -13,6 +13,11 @@ public class ExecutionQueue implements Serializable {
*/
private String queueId;
/**
* taskId
*/
private String taskId;
/**
* 执行人
*/

View File

@ -15,6 +15,11 @@ public class ExecutionQueueDetail implements Serializable {
*/
private String resourceId;
/**
* 资源id每个资源在同一个运行队列中唯一
*/
private String taskItemId;
/**
* 排序
*/

View File

@ -32,13 +32,16 @@ public class TestPlanExecutionQueue {
private String prepareReportId;
// 测试集Json
private String testPlanCollectionJson;
// 任务ID
private String taskId;
// 是否是队列的最后一个
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) {
public TestPlanExecutionQueue(long pos, String createUser, long createTime, String queueId, String queueType, String parentQueueId, String parentQueueType, String sourceID, String runMode,
String executionSource, String prepareReportId, String taskId) {
this.pos = pos;
this.createUser = createUser;
this.createTime = createTime;
@ -50,5 +53,6 @@ public class TestPlanExecutionQueue {
this.runMode = runMode;
this.executionSource = executionSource;
this.prepareReportId = prepareReportId;
this.taskId = taskId;
}
}

View File

@ -448,6 +448,8 @@ api_definition.status.continuous=连调中
api_test_case.clear.api_change=忽略本次变更差异
api_test_case.ignore.api_change=忽略全部变更差异
api_batch_task_name=用例批量执行任务
api_scenario_batch_task_name=场景批量执行
# api doc share i18n
api_doc_share.not_exist=接口文档分享不存在
api_doc_share.id.not_blank=主键不能为空

View File

@ -458,6 +458,9 @@ curl_script_is_empty=Curl script cannot be empty
curl_script_is_invalid=Curl script is invalid
curl_raw_content_is_invalid=Raw content is invalid
api_batch_task_name=Api cases batch task
api_scenario_batch_task_name=Scenarios batch task
# api doc share i18n
api_doc_share.not_exist=api doc share not exist
api_doc_share.id.not_blank=id cannot be empty

View File

@ -426,6 +426,9 @@ curl_script_is_empty=cURL脚本不能为空
curl_script_is_invalid=cURL脚本格式不正确
curl_raw_content_is_invalid=raw内容格式不正确
api_batch_task_name=用例批量执行任务
api_scenario_batch_task_name=场景批量执行
# api doc share i18n
api_doc_share.not_exist=接口文档分享不存在
api_doc_share.id.not_blank=主键不能为空

View File

@ -426,6 +426,9 @@ curl_script_is_empty=curl脚本不能爲空
curl_script_is_invalid=curl脚本格式不正確
curl_raw_content_is_invalid=raw内容格式不正確
api_batch_task_name=用例批量執行任務
api_scenario_batch_task_name=場景批量執行
# api doc share i18n
api_doc_share.not_exist=接口文檔分享不存在
api_doc_share.id.not_blank=主键不能為空

View File

@ -24,19 +24,6 @@ public class ApiExecuteResourceController {
@Resource
private ApiExecuteResourceService apiExecuteResourceService;
/**
* 获取执行脚本
*
* @param reportId
* @param testId
* @return
*/
@GetMapping("script")
@Operation(summary = "获取执行脚本")
public String getScript(@RequestParam("reportId") String reportId, @RequestParam("testId") String testId) {
return apiExecuteResourceService.getRunScript(reportId, testId);
}
/**
* 获取执行脚本
*
@ -55,11 +42,10 @@ public class ApiExecuteResourceController {
*/
@PostMapping("/file")
@Operation(summary = "下载执行所需的文件")
public void downloadFile(@RequestParam("reportId") String reportId,
@RequestParam("testId") String testId,
public void downloadFile(@RequestParam("taskItemId") String taskItemId,
@RequestBody FileRequest fileRequest,
HttpServletResponse response) throws Exception {
apiExecuteService.downloadFile(reportId, testId, fileRequest, response);
apiExecuteService.downloadFile(taskItemId, fileRequest, response);
}
}

View File

@ -17,10 +17,6 @@ import java.util.Map;
*/
@Data
public class ApiParamConfig extends ParameterConfig {
/**
* 报告ID
*/
private String reportId;
/**
* 使用全局cookie
*/

View File

@ -7,11 +7,12 @@ import io.metersphere.api.dto.debug.ApiResourceRunRequest;
import io.metersphere.api.dto.request.MsScenario;
import io.metersphere.api.dto.scenario.ApiScenarioDetail;
import io.metersphere.api.dto.scenario.ApiScenarioParseParam;
import io.metersphere.api.service.ApiCommonService;
import io.metersphere.api.service.ApiExecuteService;
import io.metersphere.api.service.scenario.ApiScenarioRunService;
import io.metersphere.sdk.constants.ApiBatchRunMode;
import io.metersphere.sdk.constants.ApiExecuteRunMode;
import io.metersphere.sdk.constants.TaskTriggerMode;
import io.metersphere.project.domain.Project;
import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.sdk.constants.*;
import io.metersphere.sdk.dto.api.task.ApiRunModeConfigDTO;
import io.metersphere.sdk.dto.api.task.TaskInfo;
import io.metersphere.sdk.dto.api.task.TaskItem;
@ -19,6 +20,8 @@ import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
import io.metersphere.sdk.util.CommonBeanFactory;
import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.LogUtils;
import io.metersphere.system.domain.ExecTask;
import io.metersphere.system.domain.ExecTaskItem;
import io.metersphere.system.schedule.BaseScheduleJob;
import io.metersphere.system.uid.IDGenerator;
import org.apache.commons.lang3.StringUtils;
@ -31,6 +34,8 @@ public class ApiScenarioScheduleJob extends BaseScheduleJob {
protected void businessExecute(JobExecutionContext context) {
ApiExecuteService apiExecuteService = CommonBeanFactory.getBean(ApiExecuteService.class);
ApiScenarioRunService apiScenarioRunService = CommonBeanFactory.getBean(ApiScenarioRunService.class);
ApiCommonService apiCommonService = CommonBeanFactory.getBean(ApiCommonService.class);
ProjectMapper projectMapper = CommonBeanFactory.getBean(ProjectMapper.class);
ApiRunModeConfigDTO apiRunModeConfigDTO = JSON.parseObject(context.getJobDetail().getJobDataMap().get("config").toString(), ApiRunModeConfigDTO.class);
ApiScenarioDetail apiScenarioDetail = apiScenarioRunService.getForRun(resourceId);
@ -58,18 +63,35 @@ public class ApiScenarioScheduleJob extends BaseScheduleJob {
ApiResourceRunRequest runRequest = apiScenarioRunService.getApiResourceRunRequest(msScenario, tmpParam);
Project project = projectMapper.selectByPrimaryKey(apiScenarioDetail.getProjectId());
ExecTask execTask = apiCommonService.newExecTask(project.getId(), userId);
execTask.setCaseCount(1L);
execTask.setTaskName(apiScenarioDetail.getName());
execTask.setOrganizationId(project.getOrganizationId());
execTask.setTriggerMode(TaskTriggerMode.SCHEDULE.name());
execTask.setTaskType(ExecTaskType.API_SCENARIO.name());
ExecTaskItem execTaskItem = apiCommonService.newExecTaskItem(execTask.getId(), project.getId(), userId);
execTaskItem.setOrganizationId(project.getOrganizationId());
execTaskItem.setResourceType(ApiExecuteResourceType.API_SCENARIO.name());
execTaskItem.setResourceId(apiScenarioDetail.getId());
execTaskItem.setResourceName(apiScenarioDetail.getName());
TaskRequestDTO taskRequest = apiScenarioRunService.getTaskRequest(IDGenerator.nextStr(), apiScenarioDetail.getId(), apiScenarioDetail.getProjectId(), ApiExecuteRunMode.SCHEDULE.name());
TaskInfo taskInfo = taskRequest.getTaskInfo();
TaskItem taskItem = taskRequest.getTaskItem();
taskInfo.getRunModeConfig().setPoolId(apiRunModeConfigDTO.getPoolId());
taskInfo.setTaskId(execTask.getId());
taskInfo.setSaveResult(true);
taskInfo.setRealTime(false);
taskInfo.setUserId(userId);
taskInfo.getRunModeConfig().setEnvironmentId(parseParam.getEnvironmentId());
taskItem.setRequestCount(tmpParam.getRequestCount().get());
taskItem.setId(execTaskItem.getId());
ApiScenarioParamConfig parseConfig = apiScenarioRunService.getApiScenarioParamConfig(msScenario.getProjectId(), parseParam, tmpParam.getScenarioParseEnvInfo());
parseConfig.setReportId(taskItem.getReportId());
parseConfig.setTaskItemId(taskItem.getId());
// 初始化报告
ApiScenarioReport scenarioReport = apiScenarioRunService.getScenarioReport(userId);

View File

@ -96,4 +96,6 @@ public interface ExtApiScenarioMapper {
List<ApiScenario> getListBySelectIds(@Param("projectId") String projectId, @Param("ids") List<String> ids, @Param("testPlanId") String testPlanId);
List<ApiScenario> selectBaseInfoByModuleId(String id);
List<ApiScenario> getNameInfo(@Param("ids") List<String> ids);
}

View File

@ -72,7 +72,14 @@
#{id}
</foreach>
</select>
<select id="getNameInfo" resultType="io.metersphere.api.domain.ApiScenario">
SELECT id, name
FROM api_scenario
WHERE id in
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
<select id="listByProviderRequest" resultMap="TestCaseProviderDTO">
SELECT
api_scenario.id,

View File

@ -59,9 +59,10 @@ public interface ExtApiTestCaseMapper {
List<ApiTestCase> getTestCaseByProvider(@Param("request") AssociateOtherCaseRequest request, @Param("deleted") boolean deleted);
List<ApiTestCase> getTagsByIds(@Param("ids") List<String> ids, @Param("deleted") boolean deleted);
List<ApiTestCase> getNameInfo(@Param("ids") List<String> ids);
List<ExecuteReportDTO> getExecuteList(@Param("request") ExecutePageRequest request);
List<OptionDTO> selectVersionOptionByIds(@Param("ids") List<String> ids);

View File

@ -971,4 +971,12 @@
#{id}
</foreach>
</select>
<select id="getNameInfo" resultType="io.metersphere.api.domain.ApiTestCase">
SELECT id,name
FROM api_test_case
WHERE id in
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
</mapper>

View File

@ -111,7 +111,7 @@ public class JmeterTestElementParser implements TestElementParser {
ThreadGroup threadGroup = new ThreadGroup();
threadGroup.setEnabled(true);
threadGroup.setName(config.getReportId());
threadGroup.setName(config.getTaskItemId());
threadGroup.setProperty(TestElement.TEST_CLASS, ThreadGroup.class.getName());
threadGroup.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ThreadGroupGui"));
threadGroup.setNumThreads(1);

View File

@ -9,6 +9,7 @@ import io.metersphere.sdk.dto.api.task.TaskInfo;
import io.metersphere.sdk.dto.queue.ExecutionQueue;
import io.metersphere.sdk.dto.queue.ExecutionQueueDetail;
import io.metersphere.sdk.util.LogUtils;
import io.metersphere.system.domain.ExecTaskItem;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
@ -24,15 +25,15 @@ import java.util.concurrent.atomic.AtomicInteger;
public class ApiBatchRunBaseService {
@Resource
private ApiExecutionQueueService apiExecutionQueueService;
/**
* 初始化执行队列
*
* @param resourceIds
* @param runModeConfig
* @return
*/
public ExecutionQueue initExecutionqueue(List<String> resourceIds, ApiRunModeConfigDTO runModeConfig, String resourceType, String userId) {
return initExecutionqueue(resourceIds, runModeConfig, resourceType, null, userId);
public ExecutionQueue initExecutionqueue(List<String> resourceIds, String resourceType, String userId) {
return initExecutionqueue(resourceIds, null, resourceType, null, userId);
}
/**
@ -59,22 +60,44 @@ public class ApiBatchRunBaseService {
queue.setQueueId(queueId);
}
queue.setParentQueueId(parentQueueId);
List<ExecutionQueueDetail> queueDetails = getExecutionQueueDetails(resourceIds);
List<ExecutionQueueDetail> queueDetails = getExecutionQueueDetailsByIds(resourceIds);
apiExecutionQueueService.insertQueue(queue, queueDetails);
return queue;
}
public ExecutionQueue initExecutionQueue(String taskId, ApiRunModeConfigDTO runModeConfig, String resourceType, String parentQueueId, String userId) {
return initExecutionQueue(taskId, null, runModeConfig, resourceType, parentQueueId, userId);
}
/**
* 初始化执行队列
*
* @param runModeConfig
* @return
*/
public ExecutionQueue initExecutionQueue(String taskId, String queueId, ApiRunModeConfigDTO runModeConfig, String resourceType, String parentQueueId, String userId) {
ExecutionQueue queue = getExecutionQueue(runModeConfig, resourceType, userId);
queue.setTaskId(taskId);
if (StringUtils.isNotBlank(queueId)) {
queue.setQueueId(queueId);
}
queue.setParentQueueId(parentQueueId);
apiExecutionQueueService.insertQueue(queue);
return queue;
}
/**
* 初始化执行队列
*
* @param resourceIds
* @param
* @return
*/
public ExecutionQueue initExecutionqueue(List<String> resourceIds, String resourceType, String userId) {
return initExecutionqueue(resourceIds, null, resourceType, null, userId);
public void initExecutionQueueDetails(String queueId, List<ExecTaskItem> execTaskItems) {
List<ExecutionQueueDetail> queueDetails = getExecutionQueueDetails(execTaskItems);
apiExecutionQueueService.insertQueueDetail(queueId, queueDetails);
}
public List<ExecutionQueueDetail> getExecutionQueueDetails(List<String> resourceIds) {
public List<ExecutionQueueDetail> getExecutionQueueDetailsByIds(List<String> resourceIds) {
List<ExecutionQueueDetail> queueDetails = new ArrayList<>();
AtomicInteger sort = new AtomicInteger(1);
for (String resourceId : resourceIds) {
@ -86,6 +109,19 @@ public class ApiBatchRunBaseService {
return queueDetails;
}
public List<ExecutionQueueDetail> getExecutionQueueDetails(List<ExecTaskItem> execTaskItems) {
List<ExecutionQueueDetail> queueDetails = new ArrayList<>();
AtomicInteger sort = new AtomicInteger(1);
execTaskItems.forEach(execTaskItem -> {
ExecutionQueueDetail queueDetail = new ExecutionQueueDetail();
queueDetail.setResourceId(execTaskItem.getResourceId());
queueDetail.setTaskItemId(execTaskItem.getId());
queueDetail.setSort(sort.getAndIncrement());
queueDetails.add(queueDetail);
});
return queueDetails;
}
private ExecutionQueue getExecutionQueue(ApiRunModeConfigDTO runModeConfig, String resourceType, String userId) {
ExecutionQueue queue = new ExecutionQueue();
queue.setQueueId(UUID.randomUUID().toString());
@ -96,7 +132,7 @@ public class ApiBatchRunBaseService {
return queue;
}
public ApiScenarioReport computeRequestRate(ApiScenarioReport report , long total) {
public ApiScenarioReport computeRequestRate(ApiScenarioReport report, long total) {
// 计算各个概率
double successRate = calculateRate(report.getSuccessCount(), total);
double errorRate = calculateRate(report.getErrorCount(), total);

View File

@ -25,8 +25,14 @@ import io.metersphere.project.dto.CommonScriptInfo;
import io.metersphere.project.service.CustomFunctionService;
import io.metersphere.project.service.FileAssociationService;
import io.metersphere.project.service.FileMetadataService;
import io.metersphere.sdk.constants.ApplicationNumScope;
import io.metersphere.sdk.constants.ExecStatus;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.domain.ExecTask;
import io.metersphere.system.domain.ExecTaskItem;
import io.metersphere.system.uid.IDGenerator;
import io.metersphere.system.uid.NumGenerator;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
@ -389,4 +395,27 @@ public class ApiCommonService {
public void setApiDefinitionExecuteInfo(AbstractMsTestElement msTestElement, ApiDefinition apiDefinition) {
setApiDefinitionExecuteInfo(msTestElement, BeanUtils.copyBean(new ApiDefinitionExecuteInfo(), apiDefinition));
}
public ExecTask newExecTask(String projectId, String userId) {
ExecTask execTask = new ExecTask();
execTask.setNum(NumGenerator.nextNum(projectId, ApplicationNumScope.TASK));
execTask.setProjectId(projectId);
execTask.setId(IDGenerator.nextStr());
execTask.setCreateTime(System.currentTimeMillis());
execTask.setCreateUser(userId);
execTask.setStatus(ExecStatus.PENDING.name());
return execTask;
}
public ExecTaskItem newExecTaskItem(String taskId, String projectId, String userId) {
ExecTaskItem execTaskItem = new ExecTaskItem();
execTaskItem.setId(IDGenerator.nextStr());
execTaskItem.setTaskId(taskId);
execTaskItem.setProjectId(projectId);
execTaskItem.setExecutor(userId);
execTaskItem.setStatus(ExecStatus.PENDING.name());
execTaskItem.setResourcePoolId(StringUtils.EMPTY);
execTaskItem.setResourcePoolNode(StringUtils.EMPTY);
return execTaskItem;
}
}

View File

@ -4,6 +4,7 @@ import io.metersphere.api.invoker.ApiExecuteCallbackServiceInvoker;
import io.metersphere.api.service.definition.ApiReportService;
import io.metersphere.api.service.scenario.ApiScenarioReportService;
import io.metersphere.sdk.constants.ApiExecuteResourceType;
import io.metersphere.sdk.constants.ApiExecuteRunMode;
import io.metersphere.sdk.constants.ExecStatus;
import io.metersphere.sdk.dto.api.task.GetRunScriptRequest;
import io.metersphere.sdk.dto.api.task.GetRunScriptResult;
@ -11,7 +12,10 @@ import io.metersphere.sdk.dto.api.task.TaskItem;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.EnumValidator;
import io.metersphere.sdk.util.LogUtils;
import io.metersphere.system.domain.ExecTaskItem;
import io.metersphere.system.mapper.ExecTaskItemMapper;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
@ -24,7 +28,7 @@ import java.util.Optional;
public class ApiExecuteResourceService {
@Resource
private ApiExecuteService apiExecuteService;
private ExecTaskItemMapper execTaskItemMapper;
@Resource
private ApiReportService apiReportService;
@Resource
@ -35,30 +39,40 @@ public class ApiExecuteResourceService {
public GetRunScriptResult getRunScript(GetRunScriptRequest request) {
TaskItem taskItem = request.getTaskItem();
String taskItemId = taskItem.getId();
String reportId = taskItem.getReportId();
String key = apiExecuteService.getTaskKey(reportId, taskItem.getResourceId());
LogUtils.info("生成并获取执行脚本: {}", key);
LogUtils.info("生成并获取执行脚本: {}", taskItem.getId());
ApiExecuteResourceType apiExecuteResourceType = EnumValidator.validateEnum(ApiExecuteResourceType.class, request.getResourceType());
switch (apiExecuteResourceType) {
case API_SCENARIO, TEST_PLAN_API_SCENARIO, PLAN_RUN_API_SCENARIO ->
apiScenarioReportService.updateReportStatus(reportId, ExecStatus.RUNNING.name());
case API_CASE, TEST_PLAN_API_CASE, PLAN_RUN_API_CASE ->
apiReportService.updateReportStatus(reportId, ExecStatus.RUNNING.name());
default -> throw new MSException("不支持的资源类型: " + request.getResourceType());
if (!ApiExecuteRunMode.isDebug(request.getRunMode())) {
// 更新任务项状态
ExecTaskItem execTaskItem = new ExecTaskItem();
execTaskItem.setId(taskItem.getId());
execTaskItem.setStartTime(System.currentTimeMillis());
execTaskItem.setStatus(ExecStatus.RUNNING.name());
execTaskItem.setThreadId(request.getThreadId());
execTaskItemMapper.updateByPrimaryKeySelective(execTaskItem);
// 非调试执行更新报告状态
switch (apiExecuteResourceType) {
case API_SCENARIO, TEST_PLAN_API_SCENARIO, PLAN_RUN_API_SCENARIO ->
apiScenarioReportService.updateReportStatus(reportId, ExecStatus.RUNNING.name());
case API_CASE, TEST_PLAN_API_CASE, PLAN_RUN_API_CASE ->
apiReportService.updateReportStatus(reportId, ExecStatus.RUNNING.name());
default -> throw new MSException("不支持的资源类型: " + request.getResourceType());
}
}
if (BooleanUtils.isFalse(request.getNeedParseScript())) {
// 已经生成过脚本直接获取
String script = stringRedisTemplate.opsForValue().get(taskItemId);
stringRedisTemplate.delete(taskItemId);
GetRunScriptResult result = new GetRunScriptResult();
result.setScript(Optional.ofNullable(script).orElse(StringUtils.EMPTY));
return result;
}
return ApiExecuteCallbackServiceInvoker.getRunScript(request.getResourceType(), request);
}
public String getRunScript(String reportId, String testId) {
String key = apiExecuteService.getTaskKey(reportId, testId);
LogUtils.info("获取执行脚本: {}", key);
String script = stringRedisTemplate.opsForValue().get(key);
stringRedisTemplate.delete(key);
apiReportService.updateReportStatus(reportId, ExecStatus.RUNNING.name());
apiScenarioReportService.updateReportStatus(reportId, ExecStatus.RUNNING.name());
return Optional.ofNullable(script).orElse(StringUtils.EMPTY);
}
}

View File

@ -31,10 +31,12 @@ import io.metersphere.sdk.file.FileRequest;
import io.metersphere.sdk.util.*;
import io.metersphere.system.config.MinioProperties;
import io.metersphere.system.controller.handler.ResultHolder;
import io.metersphere.system.domain.ExecTaskItem;
import io.metersphere.system.domain.TestResourcePool;
import io.metersphere.system.dto.pool.TestResourceDTO;
import io.metersphere.system.dto.pool.TestResourceNodeDTO;
import io.metersphere.system.dto.pool.TestResourcePoolReturnDTO;
import io.metersphere.system.mapper.ExecTaskItemMapper;
import io.metersphere.system.service.*;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
@ -43,7 +45,11 @@ import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.jmeter.util.JMeterUtils;
import org.mybatis.spring.SqlSessionUtils;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.MediaType;
@ -99,6 +105,10 @@ public class ApiExecuteService {
private ApiCommonService apiCommonService;
@Resource
private JdbcDriverPluginService jdbcDriverPluginService;
@Resource
private ExecTaskItemMapper execTaskItemMapper;
@Resource
private SqlSessionFactory sqlSessionFactory;
@PostConstruct
private void init() {
@ -122,10 +132,6 @@ public class ApiExecuteService {
}
}
public String getTaskKey(String reportId, String testId) {
return reportId + "_" + testId;
}
public TaskRequestDTO execute(ApiResourceRunRequest runRequest, TaskRequestDTO taskRequest, ApiParamConfig parameterConfig) {
TaskInfo taskInfo = taskRequest.getTaskInfo();
TaskItem taskItem = taskRequest.getTaskItem();
@ -136,12 +142,12 @@ public class ApiExecuteService {
taskInfo.setNeedParseScript(false);
// 将测试脚本缓存到 redis
String scriptRedisKey = getTaskKey(taskItem.getReportId(), taskItem.getResourceId());
String scriptRedisKey = taskItem.getId();
stringRedisTemplate.opsForValue().set(scriptRedisKey, executeScript, 1, TimeUnit.DAYS);
setTaskItemFileParam(runRequest, taskItem);
if (StringUtils.equals(taskInfo.getRunMode(), ApiExecuteRunMode.FRONTEND_DEBUG.name())) {
if (ApiExecuteRunMode.isFrontendDebug(taskInfo.getRunMode())) {
taskInfo = setTaskRequestParams(taskInfo);
// 清空mino和kafka配置信息避免前端获取
taskInfo.setMinioConfig(null);
@ -215,7 +221,6 @@ public class ApiExecuteService {
// 获取资源池
TestResourcePoolReturnDTO testResourcePoolDTO = getGetResourcePoolNodeDTO(taskInfo.getRunModeConfig(), taskInfo.getProjectId());
if (StringUtils.isNotBlank(testResourcePoolDTO.getServerUrl())) {
// 如果资源池配置了当前站点则使用资源池的
taskInfo.setMsUrl(testResourcePoolDTO.getServerUrl());
@ -223,7 +228,7 @@ public class ApiExecuteService {
// 判断是否为 K8S 资源池
boolean isK8SResourcePool = StringUtils.equals(testResourcePoolDTO.getType(), ResourcePoolTypeEnum.K8S.name());
boolean isDebugMode = StringUtils.equalsAny(taskInfo.getRunMode(), ApiExecuteRunMode.FRONTEND_DEBUG.name(), ApiExecuteRunMode.BACKEND_DEBUG.name());
boolean isDebugMode = ApiExecuteRunMode.isDebug(taskInfo.getRunMode());
if (isK8SResourcePool) {
TestResourceDTO testResourceDTO = new TestResourceDTO();
@ -237,6 +242,10 @@ public class ApiExecuteService {
}
} else {
TestResourceNodeDTO testResourceNodeDTO = getNextExecuteNode(testResourcePoolDTO);
if (!ApiExecuteRunMode.isDebug(taskInfo.getRunMode())) {
updateTaskItemNodeInfo(taskItem, testResourcePoolDTO, testResourceNodeDTO, execTaskItemMapper);
}
taskInfo.setPerTaskSize(Optional.ofNullable(testResourceNodeDTO.getSingleTaskConcurrentNumber()).orElse(3));
taskInfo.setPoolSize(testResourceNodeDTO.getConcurrentNumber());
String endpoint = MsHttpClient.getEndpoint(testResourceNodeDTO.getIp(), testResourceNodeDTO.getPort());
@ -274,6 +283,15 @@ public class ApiExecuteService {
return taskRequest;
}
private void updateTaskItemNodeInfo(TaskItem taskItem, TestResourcePoolReturnDTO testResourcePoolDTO, TestResourceNodeDTO testResourceNodeDTO, ExecTaskItemMapper execTaskItemMapper) {
// 非调试模式更新任务项的资源池信息
ExecTaskItem execTaskItem = new ExecTaskItem();
execTaskItem.setId(taskItem.getId());
execTaskItem.setResourcePoolId(testResourcePoolDTO.getId());
execTaskItem.setResourcePoolNode(StringUtils.join(testResourceNodeDTO.getIp(), ":", testResourceNodeDTO.getPort()));
execTaskItemMapper.updateByPrimaryKeySelective(execTaskItem);
}
/**
* 发送执行任务
*/
@ -321,9 +339,14 @@ public class ApiExecuteService {
TestResourceNodeDTO testResourceNode = nodesList.get(i);
TaskBatchRequestDTO subTaskRequest = distributeTasks.get(i);
String endpoint = MsHttpClient.getEndpoint(testResourceNode.getIp(), testResourceNode.getPort());
if (!ApiExecuteRunMode.isDebug(taskInfo.getRunMode())) {
batchUpdateTaskItemNodeInfo(testResourcePool, testResourceNode, subTaskRequest);
}
try {
List<String> taskKeys = subTaskRequest.getTaskItems().stream()
.map(taskItem -> taskItem.getReportId() + "_" + taskItem.getResourceId())
.map(TaskItem::getId)
.toList();
LogUtils.info("开始发送批量任务到 {} 节点执行:\n" + taskKeys, endpoint);
MsHttpClient.batchRunApi(endpoint, subTaskRequest);
@ -335,6 +358,22 @@ public class ApiExecuteService {
}
}
private void batchUpdateTaskItemNodeInfo(TestResourcePoolReturnDTO testResourcePool, TestResourceNodeDTO testResourceNode, TaskBatchRequestDTO batchRequest) {
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
try {
if (CollectionUtils.isNotEmpty(batchRequest.getTaskItems())) {
ExecTaskItemMapper batchExecTaskItemMapper = sqlSession.getMapper(ExecTaskItemMapper.class);
batchRequest.getTaskItems().forEach(taskItem -> {
// 非调试模式更新任务项的资源池信息
updateTaskItemNodeInfo(taskItem, testResourcePool, testResourceNode, batchExecTaskItemMapper);
});
}
} finally {
sqlSession.flushStatements();
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
}
protected static boolean validate() {
try {
LicenseService licenseService = CommonBeanFactory.getBean(LicenseService.class);
@ -419,11 +458,13 @@ public class ApiExecuteService {
// 设置执行参数
TaskRequestDTO taskRequest = getTaskRequest(reportId, testId, runRequest.getProjectId());
TaskInfo taskInfo = taskRequest.getTaskInfo();
taskInfo.setTaskId(reportId);
setServerInfoParam(taskInfo);
taskInfo.setRealTime(true);
taskInfo.setSaveResult(false);
taskInfo.setResourceType(ApiExecuteResourceType.API_DEBUG.name());
taskInfo.setRunMode(ApiExecuteRunMode.BACKEND_DEBUG.name());
taskRequest.getTaskItem().setId(reportId);
return execute(apiRunRequest, taskRequest, new ApiParamConfig());
}
@ -644,9 +685,8 @@ public class ApiExecuteService {
return (String) configMap.get(ProjectApplicationType.API.API_RESOURCE_POOL_ID.name());
}
public void downloadFile(String reportId, String testId, FileRequest fileRequest, HttpServletResponse response) throws Exception {
String key = getTaskKey(reportId, testId);
if (BooleanUtils.isTrue(stringRedisTemplate.hasKey(key))) {
public void downloadFile(String taskItemId, FileRequest fileRequest, HttpServletResponse response) throws Exception {
if (BooleanUtils.isTrue(stringRedisTemplate.hasKey(taskItemId))) {
FileRepository repository = StringUtils.isBlank(fileRequest.getStorage()) ? FileCenter.getDefaultRepository()
: FileCenter.getRepository(fileRequest.getStorage());
write2Response(repository.getFileAsStream(fileRequest), response);

View File

@ -215,10 +215,13 @@ public class ApiDebugService extends MoveNodeService {
TaskRequestDTO taskRequest = apiExecuteService.getTaskRequest(request.getReportId(), request.getId(), request.getProjectId());
TaskInfo taskInfo = taskRequest.getTaskInfo();
taskInfo.setTaskId(request.getReportId());
taskInfo.setSaveResult(false);
taskInfo.setRealTime(true);
taskInfo.setResourceType(ApiResourceType.API_DEBUG.name());
taskInfo.setRunMode(apiExecuteService.getDebugRunModule(request.getFrontendDebug()));
taskRequest.getTaskItem().setId(request.getReportId());
apiParamConfig.setTaskItemId(taskRequest.getTaskItem().getId());
return apiExecuteService.apiExecute(runRequest, taskRequest, apiParamConfig);
}

View File

@ -1195,10 +1195,12 @@ public class ApiDefinitionService extends MoveNodeService {
TaskRequestDTO taskRequest = apiExecuteService.getTaskRequest(request.getReportId(), request.getId(), request.getProjectId());
TaskInfo taskInfo = taskRequest.getTaskInfo();
taskInfo.setTaskId(request.getReportId());
taskInfo.setSaveResult(false);
taskInfo.setRealTime(true);
taskInfo.setResourceType(ApiResourceType.API.name());
taskInfo.setRunMode(apiExecuteService.getDebugRunModule(request.getFrontendDebug()));
taskRequest.getTaskItem().setId(request.getReportId());
AbstractMsTestElement msTestElement = runRequest.getTestElement();

View File

@ -66,6 +66,10 @@ public class ApiReportService {
@Resource
private ApiReportNoticeService apiReportNoticeService;
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void insertApiReport(ApiReport report) {
apiReportMapper.insertSelective(report);
}
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void insertApiReport(List<ApiReport> reports, List<ApiTestCaseRecord> records) {

View File

@ -4,27 +4,27 @@ import io.metersphere.api.domain.*;
import io.metersphere.api.dto.definition.ApiTestCaseBatchRunRequest;
import io.metersphere.api.mapper.*;
import io.metersphere.api.service.ApiBatchRunBaseService;
import io.metersphere.api.service.ApiCommonService;
import io.metersphere.api.service.ApiExecuteService;
import io.metersphere.api.service.queue.ApiExecutionQueueService;
import io.metersphere.api.service.queue.ApiExecutionSetService;
import io.metersphere.project.domain.Project;
import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.sdk.constants.*;
import io.metersphere.sdk.dto.api.task.*;
import io.metersphere.sdk.dto.queue.ExecutionQueue;
import io.metersphere.sdk.dto.queue.ExecutionQueueDetail;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.DateUtils;
import io.metersphere.sdk.util.LogUtils;
import io.metersphere.sdk.util.SubListUtils;
import io.metersphere.sdk.util.*;
import io.metersphere.system.domain.ExecTask;
import io.metersphere.system.domain.ExecTaskItem;
import io.metersphere.system.service.BaseTaskHubService;
import io.metersphere.system.uid.IDGenerator;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -39,6 +39,8 @@ public class ApiTestCaseBatchRunService {
@Resource
private ApiTestCaseService apiTestCaseService;
@Resource
private ApiCommonService apiCommonService;
@Resource
private ApiExecuteService apiExecuteService;
@Resource
private ApiExecutionQueueService apiExecutionQueueService;
@ -54,6 +56,12 @@ public class ApiTestCaseBatchRunService {
private ApiReportDetailMapper apiReportDetailMapper;
@Resource
private ApiReportStepMapper apiReportStepMapper;
@Resource
private ProjectMapper projectMapper;
@Resource
private BaseTaskHubService baseTaskHubService;
public static final int TASK_BATCH_SIZE = 600;
/**
* 异步批量执行
@ -92,24 +100,38 @@ public class ApiTestCaseBatchRunService {
List<String> ids = apiTestCaseService.doSelectIds(request, false);
ApiRunModeConfigDTO runModeConfig = getRunModeConfig(request);
Project project = projectMapper.selectByPrimaryKey(request.getProjectId());
// 初始化任务
ExecTask execTask = initExecTask(ids, runModeConfig, project, userId);
if (runModeConfig.isIntegratedReport()) {
// 初始化集成报告
initIntegratedReport(runModeConfig, ids, userId, request.getProjectId());
List<ApiTestCase> apiTestCases = new ArrayList<>(ids.size());
// 分批查询
SubListUtils.dealForSubList(ids, 100, subIds -> apiTestCases.addAll(extApiTestCaseMapper.getApiCaseExecuteInfoByIds(subIds)));
Map<String, ApiTestCase> apiCaseMap = apiTestCases.stream()
.collect(Collectors.toMap(ApiTestCase::getId, Function.identity()));
// 初始化集成报告步骤
initApiReportSteps(ids, apiCaseMap, runModeConfig.getCollectionReport().getReportId());
initIntegratedReport(runModeConfig, userId, request.getProjectId());
}
// 先初始化集成报告设置好报告ID再初始化执行队列
ExecutionQueue queue = apiBatchRunBaseService.initExecutionqueue(ids, runModeConfig, ApiExecuteResourceType.API_CASE.name(), userId);
ExecutionQueue queue = apiBatchRunBaseService.initExecutionQueue(execTask.getId(), runModeConfig, ApiExecuteResourceType.API_CASE.name(), null, userId);
// 分批查询
SubListUtils.dealForSubList(ids, TASK_BATCH_SIZE, subIds -> {
List<ApiTestCase> apiTestCases = getOrderApiTestCases(subIds, runModeConfig);
// 初始化任务项
List<ExecTaskItem> execTaskItems = initExecTaskItem(apiTestCases, userId, project, execTask);
// 初始化队列项
apiBatchRunBaseService.initExecutionQueueDetails(queue.getQueueId(), execTaskItems);
if (runModeConfig.isIntegratedReport()) {
String reportId = runModeConfig.getCollectionReport().getReportId();
// 初始化集成报告和用例的关联关系
initIntegratedReportCaseRecord(reportId, runModeConfig, subIds);
// 初始化集成报告步骤
initApiReportSteps(apiTestCases, reportId);
}
});
// 执行第一个任务
ExecutionQueueDetail nextDetail = apiExecutionQueueService.getNextDetail(queue.getQueueId());
@ -120,6 +142,35 @@ public class ApiTestCaseBatchRunService {
executeNextTask(queue, nextDetail);
}
private List<ExecTaskItem> initExecTaskItem(List<ApiTestCase> apiTestCases, String userId, Project project, ExecTask execTask) {
List<ExecTaskItem> execTaskItems = new ArrayList<>(apiTestCases.size());
for (ApiTestCase apiTestCase : apiTestCases) {
ExecTaskItem execTaskItem = apiCommonService.newExecTaskItem(execTask.getId(), project.getId(), userId);
execTaskItem.setOrganizationId(project.getOrganizationId());
execTaskItem.setResourceType(ApiExecuteResourceType.API_CASE.name());
execTaskItem.setResourceId(apiTestCase.getId());
execTaskItem.setResourceName(apiTestCase.getName());
execTaskItems.add(execTaskItem);
}
baseTaskHubService.insertExecTaskDetail(execTaskItems);
return execTaskItems;
}
private ExecTask initExecTask(List<String> ids, ApiRunModeConfigDTO runModeConfig, Project project, String userId) {
ExecTask execTask = apiCommonService.newExecTask(project.getId(), userId);
execTask.setCaseCount(Long.valueOf(ids.size()));
if (runModeConfig.isIntegratedReport()) {
execTask.setTaskName(runModeConfig.getCollectionReport().getReportName());
} else {
execTask.setTaskName(Translator.get("api_batch_task_name"));
}
execTask.setOrganizationId(project.getOrganizationId());
execTask.setTriggerMode(TaskTriggerMode.MANUAL.name());
execTask.setTaskType(ExecTaskType.API_CASE_BATCH.name());
baseTaskHubService.insertExecTask(execTask);
return execTask;
}
/**
* 并行批量执行
*
@ -137,25 +188,65 @@ public class ApiTestCaseBatchRunService {
apiExecutionSetService.initSet(apiReport.getId(), ids);
}
List<ApiTestCase> apiTestCases = new ArrayList<>(ids.size());
// todo
// 集成报告执行前先设置成 RUNNING
setRunningIntegrateReport(runModeConfig);
Project project = projectMapper.selectByPrimaryKey(request.getProjectId());
// 初始化任务
ExecTask execTask = initExecTask(ids, runModeConfig, project, userId);
// 分批查询
SubListUtils.dealForSubList(ids, 100, subIds -> apiTestCases.addAll(extApiTestCaseMapper.getApiCaseExecuteInfoByIds(subIds)));
SubListUtils.dealForSubList(ids, TASK_BATCH_SIZE, subIds -> {
List<ApiTestCase> apiTestCases = getOrderApiTestCases(subIds, runModeConfig);
// 初始化任务项
Map<String, String> resourceExecTaskItemMap = initExecTaskItem(apiTestCases, userId, project, execTask)
.stream()
.collect(Collectors.toMap(ExecTaskItem::getResourceId, ExecTaskItem::getId));
// 初始化报告返回用例和报告的 map
Map<String, String> caseReportMap = initParallelReport(runModeConfig, apiTestCases, userId);
List<TaskItem> taskItems = new ArrayList<>(subIds.size());
for (ApiTestCase apiTestCase : apiTestCases) {
// 如果是集成报告则生成唯一的虚拟ID非集成报告使用单用例的报告ID
String reportId = runModeConfig.isIntegratedReport()
? runModeConfig.getCollectionReport().getReportId() + IDGenerator.nextStr()
: caseReportMap.get(apiTestCase.getId());
TaskItem taskItem = apiExecuteService.getTaskItem(reportId, apiTestCase.getId());
taskItem.setId(resourceExecTaskItemMap.get(apiTestCase.getId()));
taskItem.setRequestCount(1L);
taskItems.add(taskItem);
}
TaskBatchRequestDTO taskRequest = getTaskBatchRequestDTO(request.getProjectId(), runModeConfig);
taskRequest.getTaskInfo().setTaskId(execTask.getId());
taskRequest.setTaskItems(taskItems);
apiExecuteService.batchExecute(taskRequest);
});
}
/**
* 获取有序的用例
* @param ids
* @return
*/
private List<ApiTestCase> getOrderApiTestCases(List<String> ids, ApiRunModeConfigDTO runModeConfig) {
List<ApiTestCase> apiTestCases = new ArrayList<>(TASK_BATCH_SIZE);
// 分批查询
List<ApiTestCase> finalApiTestCases = apiTestCases;
SubListUtils.dealForSubList(ids, 200, subIds -> finalApiTestCases.addAll(extApiTestCaseMapper.getApiCaseExecuteInfoByIds(subIds)));
Map<String, ApiTestCase> apiCaseMap = apiTestCases.stream()
.collect(Collectors.toMap(ApiTestCase::getId, Function.identity()));
// 初始化报告返回用例和报告的 map
Map<String, String> caseReportMap = initParallelReport(ids, runModeConfig, apiTestCases, apiCaseMap, userId);
apiTestCases = new ArrayList<>(ids.size());
// 集成报告执行前先设置成 RUNNING
setRunningIntegrateReport(runModeConfig);
List<TaskItem> taskItems = new ArrayList<>(ids.size());
// 这里ID顺序和队列的ID顺序保持一致
for (String id : ids) {
// 按照ID顺序排序
ApiTestCase apiTestCase = apiCaseMap.get(id);
if (apiTestCase == null) {
if (runModeConfig.isIntegratedReport()) {
// 用例不存在则在执行集合中删除
@ -164,22 +255,12 @@ public class ApiTestCaseBatchRunService {
LogUtils.info("当前执行任务的用例已删除 {}", id);
break;
}
// 如果是集成报告则生成唯一的虚拟ID非集成报告使用单用例的报告ID
String reportId = runModeConfig.isIntegratedReport()
? runModeConfig.getCollectionReport().getReportId() + IDGenerator.nextStr()
: caseReportMap.get(id);
TaskItem taskItem = apiExecuteService.getTaskItem(reportId, id);
taskItem.setRequestCount(1L);
taskItems.add(taskItem);
apiTestCases.add(apiTestCase);
}
TaskBatchRequestDTO taskRequest = getTaskBatchRequestDTO(request.getProjectId(), runModeConfig);
taskRequest.setTaskItems(taskItems);
apiExecuteService.batchExecute(taskRequest);
return apiTestCases;
}
/**
* 集成报告执行前先设置成 RUNNING
*
@ -191,12 +272,12 @@ public class ApiTestCaseBatchRunService {
}
}
private Map<String, String> initParallelReport(List<String> ids, ApiRunModeConfigDTO runModeConfig, List<ApiTestCase> apiTestCases, Map<String, ApiTestCase> apiCaseMap, String userId) {
private Map<String, String> initParallelReport(ApiRunModeConfigDTO runModeConfig, List<ApiTestCase> apiTestCases, String userId) {
// 先初始化所有报告
if (runModeConfig.isIntegratedReport()) {
// 获取集成报告ID
String integratedReportId = runModeConfig.getCollectionReport().getReportId();
initApiReportSteps(ids, apiCaseMap, integratedReportId);
initApiReportSteps(apiTestCases, integratedReportId);
return null;
} else {
// 初始化非集成报告
@ -209,14 +290,12 @@ public class ApiTestCaseBatchRunService {
/**
* 初始化集成报告的报告步骤
*
* @param ids
* @param apiCaseMap
* @param reportId
*/
private void initApiReportSteps(List<String> ids, Map<String, ApiTestCase> apiCaseMap, String reportId) {
private void initApiReportSteps(List<ApiTestCase> apiTestCases, String reportId) {
AtomicLong sort = new AtomicLong(1);
List<ApiReportStep> apiReportSteps = ids.stream()
.map(id -> getApiReportStep(apiCaseMap.get(id), reportId, sort.getAndIncrement()))
List<ApiReportStep> apiReportSteps = apiTestCases.stream()
.map(apiTestCase -> getApiReportStep(apiTestCase, reportId, sort.getAndIncrement()))
.collect(Collectors.toList());
apiReportService.insertApiReportStep(apiReportSteps);
}
@ -265,6 +344,43 @@ public class ApiTestCaseBatchRunService {
return apiReport;
}
/**
* 预生成用例的执行报告
*
* @param runModeConfig
* @return
*/
private ApiReport initIntegratedReport(ApiRunModeConfigDTO runModeConfig, String userId, String projectId) {
ApiReport apiReport = getApiReport(runModeConfig, userId);
apiReport.setName(runModeConfig.getCollectionReport().getReportName() + "_" + DateUtils.getTimeString(System.currentTimeMillis()));
apiReport.setIntegrated(true);
apiReport.setProjectId(projectId);
apiReportService.insertApiReport(apiReport);
// 设置集成报告执行参数
runModeConfig.getCollectionReport().setReportId(apiReport.getId());
return apiReport;
}
/**
* 预生成用例的执行报告
*
* @param runModeConfig
* @param ids
* @return
*/
private void initIntegratedReportCaseRecord(String reportId, ApiRunModeConfigDTO runModeConfig, List<String> ids) {
// 初始化集成报告与用例的关联关系
List<ApiTestCaseRecord> records = ids.stream().map(id -> {
ApiTestCaseRecord record = new ApiTestCaseRecord();
record.setApiReportId(reportId);
record.setApiTestCaseId(id);
return record;
}).toList();
apiReportService.insertApiReport(List.of(), records);
// 设置集成报告执行参数
runModeConfig.getCollectionReport().setReportId(reportId);
}
/**
* 执行串行的下一个任务
*
@ -274,6 +390,7 @@ public class ApiTestCaseBatchRunService {
public void executeNextTask(ExecutionQueue queue, ExecutionQueueDetail queueDetail) {
ApiRunModeConfigDTO runModeConfig = queue.getRunModeConfig();
String resourceId = queueDetail.getResourceId();
String taskItemId = queueDetail.getTaskItemId();
ApiTestCase apiTestCase = apiTestCaseMapper.selectByPrimaryKey(resourceId);
@ -291,9 +408,11 @@ public class ApiTestCaseBatchRunService {
}
TaskRequestDTO taskRequest = getTaskRequestDTO(reportId, apiTestCase, runModeConfig);
taskRequest.getTaskInfo().setTaskId(queue.getTaskId());
taskRequest.getTaskInfo().setQueueId(queue.getQueueId());
taskRequest.getTaskInfo().setUserId(queue.getUserId());
taskRequest.getTaskItem().setRequestCount(1L);
taskRequest.getTaskItem().setId(taskItemId);
apiExecuteService.execute(taskRequest);
}

View File

@ -32,6 +32,8 @@ import io.metersphere.sdk.dto.api.task.*;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.mapper.EnvironmentMapper;
import io.metersphere.sdk.util.*;
import io.metersphere.system.domain.ExecTask;
import io.metersphere.system.domain.ExecTaskItem;
import io.metersphere.system.domain.User;
import io.metersphere.system.dto.OperationHistoryDTO;
import io.metersphere.system.dto.request.OperationHistoryRequest;
@ -40,6 +42,7 @@ import io.metersphere.system.dto.sdk.request.PosRequest;
import io.metersphere.system.log.constants.OperationLogModule;
import io.metersphere.system.mapper.UserMapper;
import io.metersphere.system.notice.constants.NoticeConstants;
import io.metersphere.system.service.BaseTaskHubService;
import io.metersphere.system.service.OperationHistoryService;
import io.metersphere.system.service.UserLoginService;
import io.metersphere.system.uid.IDGenerator;
@ -116,6 +119,8 @@ public class ApiTestCaseService extends MoveNodeService {
private FunctionalCaseTestMapper functionalCaseTestMapper;
@Resource
private UserMapper userMapper;
@Resource
private BaseTaskHubService baseTaskHubService;
private static final String CASE_TABLE = "api_test_case";
@ -719,6 +724,22 @@ public class ApiTestCaseService extends MoveNodeService {
*/
public TaskRequestDTO executeRun(ApiResourceRunRequest runRequest, ApiTestCase apiTestCase, String reportId, String userId) {
String poolId = apiExecuteService.getProjectApiResourcePoolId(apiTestCase.getProjectId());
Project project = projectMapper.selectByPrimaryKey(apiTestCase.getProjectId());
ExecTask execTask = apiCommonService.newExecTask(project.getId(), userId);
execTask.setCaseCount(1L);
execTask.setTaskName(apiTestCase.getName());
execTask.setOrganizationId(project.getOrganizationId());
execTask.setTriggerMode(TaskTriggerMode.MANUAL.name());
execTask.setTaskType(ExecTaskType.API_CASE.name());
ExecTaskItem execTaskItem = apiCommonService.newExecTaskItem(execTask.getId(), project.getId(), userId);
execTaskItem.setOrganizationId(project.getOrganizationId());
execTaskItem.setResourceType(ApiExecuteResourceType.API_CASE.name());
execTaskItem.setResourceId(apiTestCase.getId());
execTaskItem.setResourceName(apiTestCase.getName());
baseTaskHubService.insertExecTaskAndDetail(execTask, execTaskItem);
TaskRequestDTO taskRequest = getTaskRequest(reportId, apiTestCase.getId(), apiTestCase.getProjectId(), ApiExecuteRunMode.RUN.name());
TaskItem taskItem = taskRequest.getTaskItem();
@ -726,6 +747,8 @@ public class ApiTestCaseService extends MoveNodeService {
taskInfo.getRunModeConfig().setPoolId(poolId);
taskInfo.setSaveResult(true);
taskInfo.setUserId(userId);
taskInfo.setTaskId(execTask.getId());
taskItem.setId(execTaskItem.getId());
if (StringUtils.isEmpty(taskItem.getReportId())) {
taskInfo.setRealTime(false);
@ -752,9 +775,11 @@ public class ApiTestCaseService extends MoveNodeService {
public TaskRequestDTO debug(ApiCaseRunRequest request, String userId) {
TaskRequestDTO taskRequest = getTaskRequest(request.getReportId(), request.getId(),
request.getProjectId(), apiExecuteService.getDebugRunModule(request.getFrontendDebug()));
taskRequest.getTaskInfo().setTaskId(UUID.randomUUID().toString());
taskRequest.getTaskInfo().setSaveResult(false);
taskRequest.getTaskInfo().setRealTime(true);
taskRequest.getTaskInfo().setUserId(userId);
taskRequest.getTaskItem().setId(UUID.randomUUID().toString());
ApiResourceRunRequest runRequest = apiExecuteService.getApiResourceRunRequest(request);
@ -771,6 +796,7 @@ public class ApiTestCaseService extends MoveNodeService {
apiParamConfig.setEnvConfig(environmentService.get(envId));
taskRequest.getTaskInfo().getRunModeConfig().setEnvironmentId(envId);
apiParamConfig.setTaskItemId(taskRequest.getTaskItem().getId());
// 设置 method 等信息
apiCommonService.setApiDefinitionExecuteInfo(runRequest.getTestElement(), apiDefinition);
@ -872,8 +898,12 @@ public class ApiTestCaseService extends MoveNodeService {
}
public ApiTestCaseRecord getApiTestCaseRecord(ApiTestCase apiTestCase, ApiReport apiReport) {
return getApiTestCaseRecord(apiTestCase.getId(), apiReport);
}
public ApiTestCaseRecord getApiTestCaseRecord(String caseId, ApiReport apiReport) {
ApiTestCaseRecord apiTestCaseRecord = new ApiTestCaseRecord();
apiTestCaseRecord.setApiTestCaseId(apiTestCase.getId());
apiTestCaseRecord.setApiTestCaseId(caseId);
apiTestCaseRecord.setApiReportId(apiReport.getId());
return apiTestCaseRecord;
}

View File

@ -34,6 +34,20 @@ public class ApiExecutionQueueService {
stringRedisTemplate.expire(QUEUE_DETAIL_PREFIX + queue.getQueueId(), 1, TimeUnit.DAYS);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void insertQueue(ExecutionQueue queue) {
// 保存队列信息
stringRedisTemplate.opsForValue().setIfAbsent(QUEUE_PREFIX + queue.getQueueId(), JSON.toJSONString(queue), 1, TimeUnit.DAYS);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void insertQueueDetail(String queueId, List<ExecutionQueueDetail> queueDetails) {
// 保存队列详情信息
List<String> queueStrItems = queueDetails.stream().map(JSON::toJSONString).toList();
stringRedisTemplate.opsForList().rightPushAll(QUEUE_DETAIL_PREFIX + queueId, queueStrItems);
stringRedisTemplate.expire(QUEUE_DETAIL_PREFIX + queueId, 1, TimeUnit.DAYS);
}
/**
* 获取下一个节点
*/

View File

@ -10,17 +10,20 @@ import io.metersphere.api.mapper.ApiScenarioMapper;
import io.metersphere.api.mapper.ApiScenarioReportMapper;
import io.metersphere.api.mapper.ExtApiScenarioMapper;
import io.metersphere.api.service.ApiBatchRunBaseService;
import io.metersphere.api.service.ApiCommonService;
import io.metersphere.api.service.ApiExecuteService;
import io.metersphere.api.service.queue.ApiExecutionQueueService;
import io.metersphere.api.service.queue.ApiExecutionSetService;
import io.metersphere.project.domain.Project;
import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.sdk.constants.*;
import io.metersphere.sdk.dto.api.task.*;
import io.metersphere.sdk.dto.queue.ExecutionQueue;
import io.metersphere.sdk.dto.queue.ExecutionQueueDetail;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.DateUtils;
import io.metersphere.sdk.util.LogUtils;
import io.metersphere.sdk.util.SubListUtils;
import io.metersphere.sdk.util.*;
import io.metersphere.system.domain.ExecTask;
import io.metersphere.system.domain.ExecTaskItem;
import io.metersphere.system.service.BaseTaskHubService;
import io.metersphere.system.uid.IDGenerator;
import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
@ -59,6 +62,14 @@ public class ApiScenarioBatchRunService {
private ApiScenarioMapper apiScenarioMapper;
@Resource
private ApiScenarioRunService apiScenarioRunService;
@Resource
private ProjectMapper projectMapper;
@Resource
private ApiCommonService apiCommonService;
@Resource
private BaseTaskHubService baseTaskHubService;
public static final int TASK_BATCH_SIZE = 600;
/**
* 异步批量执行
@ -96,19 +107,46 @@ public class ApiScenarioBatchRunService {
public void serialExecute(ApiScenarioBatchRunRequest request, String userId) {
List<String> ids = apiScenarioService.doSelectIds(request, false);
ApiRunModeConfigDTO runModeConfig = getRunModeConfig(request);
Project project = projectMapper.selectByPrimaryKey(request.getProjectId());
// 初始化任务
ExecTask execTask = initExecTask(ids, runModeConfig, project, userId);
// 初始化集成报告
if (runModeConfig.isIntegratedReport()) {
initIntegratedReport(runModeConfig, ids, userId, request.getProjectId());
// 初始化集合报告步骤
initReport(ids, runModeConfig, userId);
initIntegratedReport(runModeConfig, userId, request.getProjectId());
}
// 先初始化集成报告设置好报告ID再初始化执行队列
ExecutionQueue queue = apiBatchRunBaseService.initExecutionQueue(execTask.getId(), runModeConfig,
ApiExecuteResourceType.API_SCENARIO.name(), null, userId);
// 分批查询
SubListUtils.dealForSubList(ids, TASK_BATCH_SIZE, subIds -> {
List<ApiScenario> apiScenarios = getOrderScenarios(subIds, runModeConfig);
// 初始化任务项
List<ExecTaskItem> execTaskItems = initExecTaskItem(subIds, apiScenarios, userId, project, execTask);
if (runModeConfig.isIntegratedReport()) {
String reportId = runModeConfig.getCollectionReport().getReportId();
// 初始化集合报告和场景的关联关系
initIntegratedReportCaseRecord(reportId, subIds);
// 集合报告初始化一级步骤
initApiScenarioReportStep(apiScenarios, reportId);
} else {
// 非集合报告初始化独立报告执行时初始化步骤
initScenarioReport(runModeConfig, apiScenarios, userId);
}
// 初始化队列项
apiBatchRunBaseService.initExecutionQueueDetails(queue.getQueueId(), execTaskItems);
});
// todo
// 集成报告执行前先设置成 RUNNING
setRunningIntegrateReport(runModeConfig);
// 先初始化集成报告设置好报告ID再初始化执行队列
ExecutionQueue queue = apiBatchRunBaseService.initExecutionqueue(ids, runModeConfig, ApiExecuteResourceType.API_SCENARIO.name(), userId);
// 执行第一个任务
ExecutionQueueDetail nextDetail = apiExecutionQueueService.getNextDetail(queue.getQueueId());
executeNextTask(queue, nextDetail);
@ -124,63 +162,119 @@ public class ApiScenarioBatchRunService {
ApiRunModeConfigDTO runModeConfig = getRunModeConfig(request);
// 集成报告执行前先设置成 RUNNING
setRunningIntegrateReport(runModeConfig);
Project project = projectMapper.selectByPrimaryKey(request.getProjectId());
// 初始化任务
ExecTask execTask = initExecTask(ids, runModeConfig, project, userId);
if (runModeConfig.isIntegratedReport()) {
// 初始化集成报告
ApiScenarioReport apiScenarioReport = initIntegratedReport(runModeConfig, ids, userId, request.getProjectId());
ApiScenarioReport apiScenarioReport = initIntegratedReport(runModeConfig, userId, request.getProjectId());
// 集成报告才需要初始化执行集合用于统计整体执行情况
apiExecutionSetService.initSet(apiScenarioReport.getId(), ids);
}
Map<String, String> scenarioReportMap = initReport(ids, runModeConfig, userId);
// 分批查询
SubListUtils.dealForSubList(ids, TASK_BATCH_SIZE, subIds -> {
List<ApiScenario> apiScenarios = getOrderScenarios(subIds, runModeConfig);
Map<String, String> caseReportMap = null;
if (runModeConfig.isIntegratedReport()) {
// 集合报告初始化一级步骤
initApiScenarioReportStep(apiScenarios, runModeConfig.getCollectionReport().getReportId());
} else {
// 非集合报告初始化独立报告执行时初始化步骤
caseReportMap = initScenarioReport(runModeConfig, apiScenarios, userId);
}
// 集成报告执行前先设置成 RUNNING
setRunningIntegrateReport(runModeConfig);
// 初始化任务项
Map<String, String> resourceExecTaskItemMap = initExecTaskItem(subIds, apiScenarios, userId, project, execTask)
.stream()
.collect(Collectors.toMap(ExecTaskItem::getResourceId, ExecTaskItem::getId));
List<TaskItem> taskItems = ids.stream()
.map(id -> apiExecuteService.getTaskItem(
runModeConfig.isIntegratedReport()
? runModeConfig.getCollectionReport().getReportId() + IDGenerator.nextStr()
: scenarioReportMap.get(id), id
))
.toList();
List<TaskItem> taskItems = new ArrayList<>(ids.size());
TaskBatchRequestDTO taskRequest = getTaskBatchRequestDTO(request.getProjectId(), runModeConfig);
taskRequest.setTaskItems(taskItems);
taskRequest.getTaskInfo().setUserId(userId);
for (ApiScenario apiScenario : apiScenarios) {
// 如果是集成报告则生成唯一的虚拟ID非集成报告使用单用例的报告ID
String reportId = runModeConfig.isIntegratedReport()
? runModeConfig.getCollectionReport().getReportId() + IDGenerator.nextStr()
: caseReportMap.get(apiScenario.getId());
apiExecuteService.batchExecute(taskRequest);
TaskItem taskItem = apiExecuteService.getTaskItem(reportId, apiScenario.getId());
taskItem.setId(resourceExecTaskItemMap.get(apiScenario.getId()));
taskItem.setRequestCount(1L);
taskItems.add(taskItem);
}
TaskBatchRequestDTO taskRequest = getTaskBatchRequestDTO(request.getProjectId(), runModeConfig);
taskRequest.getTaskInfo().setTaskId(execTask.getId());
taskRequest.getTaskInfo().setUserId(userId);
taskRequest.setTaskItems(taskItems);
apiExecuteService.batchExecute(taskRequest);
});
}
private Map<String, String> initReport(List<String> ids, ApiRunModeConfigDTO runModeConfig, String userId) {
List<ApiScenario> apiScenarios = new ArrayList<>(ids.size());
/**
* 获取有序的用例
* @param ids
* @return
*/
private List<ApiScenario> getOrderScenarios(List<String> ids, ApiRunModeConfigDTO runModeConfig) {
List<ApiScenario> apiScenarios = new ArrayList<>(TASK_BATCH_SIZE);
// 分批查询
List<ApiScenario> finalApiScenarios = apiScenarios;
SubListUtils.dealForSubList(ids, 100, subIds -> finalApiScenarios.addAll(extApiScenarioMapper.getScenarioExecuteInfoByIds(subIds)));
SubListUtils.dealForSubList(ids, 200, subIds -> finalApiScenarios.addAll(extApiScenarioMapper.getScenarioExecuteInfoByIds(subIds)));
Map<String, ApiScenario> apiScenarioMap = apiScenarios.stream()
.collect(Collectors.toMap(ApiScenario::getId, Function.identity()));
apiScenarios = new ArrayList<>(ids.size());
for (String id : ids) {
// 按照ID顺序排序
ApiScenario apiScenario = apiScenarioMap.get(id);
if (apiScenario == null) {
if (runModeConfig.isIntegratedReport()) {
// 用例不存在则在执行集合中删除
apiExecutionSetService.removeItem(runModeConfig.getCollectionReport().getReportId(), id);
}
LogUtils.info("当前执行任务的用例已删除 {}", id);
break;
}
apiScenarios.add(apiScenario);
}
if (runModeConfig.isIntegratedReport()) {
// 集合报告初始化一级步骤
initApiScenarioReportStep(apiScenarios, runModeConfig.getCollectionReport().getReportId());
return null;
} else {
// 非集合报告初始化独立报告执行时初始化步骤
return initScenarioReport(runModeConfig, apiScenarios, userId);
}
return apiScenarios;
}
private ExecTask initExecTask(List<String> ids, ApiRunModeConfigDTO runModeConfig, Project project, String userId) {
ExecTask execTask = apiCommonService.newExecTask(project.getId(), userId);
execTask.setCaseCount(Long.valueOf(ids.size()));
if (runModeConfig.isIntegratedReport()) {
execTask.setTaskName(runModeConfig.getCollectionReport().getReportName());
} else {
execTask.setTaskName(Translator.get("api_scenario_batch_task_name"));
}
execTask.setOrganizationId(project.getOrganizationId());
execTask.setTriggerMode(TaskTriggerMode.MANUAL.name());
execTask.setTaskType(ExecTaskType.API_SCENARIO_BATCH.name());
baseTaskHubService.insertExecTask(execTask);
return execTask;
}
private List<ExecTaskItem> initExecTaskItem(List<String> ids, List<ApiScenario> apiScenarios, String userId, Project project, ExecTask execTask) {
List<ExecTaskItem> execTaskItems = new ArrayList<>(ids.size());
for (ApiScenario apiScenario : apiScenarios) {
ExecTaskItem execTaskItem = apiCommonService.newExecTaskItem(execTask.getId(), project.getId(), userId);
execTaskItem.setOrganizationId(project.getOrganizationId());
execTaskItem.setResourceType(ApiExecuteResourceType.API_SCENARIO.name());
execTaskItem.setResourceId(apiScenario.getId());
execTaskItem.setResourceName(apiScenario.getName());
execTaskItems.add(execTaskItem);
}
baseTaskHubService.insertExecTaskDetail(execTaskItems);
return execTaskItems;
}
/**
* 集成报告执行前先设置成 RUNNING
@ -223,27 +317,30 @@ public class ApiScenarioBatchRunService {
* 预生成用例的执行报告
*
* @param runModeConfig
* @param ids
* @return
*/
private ApiScenarioReport initIntegratedReport(ApiRunModeConfigDTO runModeConfig, List<String> ids, String userId, String projectId) {
private ApiScenarioReport initIntegratedReport(ApiRunModeConfigDTO runModeConfig, String userId, String projectId) {
ApiScenarioReport apiScenarioReport = getScenarioReport(runModeConfig, userId);
apiScenarioReport.setName(runModeConfig.getCollectionReport().getReportName() + "_" + DateUtils.getTimeString(System.currentTimeMillis()));
apiScenarioReport.setIntegrated(true);
apiScenarioReport.setProjectId(projectId);
// 初始化集成报告与用例的关联关系
List<ApiScenarioRecord> records = ids.stream().map(id -> {
ApiScenarioRecord scenarioRecord = new ApiScenarioRecord();
scenarioRecord.setApiScenarioReportId(apiScenarioReport.getId());
scenarioRecord.setApiScenarioId(id);
return scenarioRecord;
}).toList();
apiScenarioReportService.insertApiScenarioReport(List.of(apiScenarioReport), records);
apiScenarioReportMapper.insertSelective(apiScenarioReport);
// 设置集成报告执行参数
runModeConfig.getCollectionReport().setReportId(apiScenarioReport.getId());
return apiScenarioReport;
}
private void initIntegratedReportCaseRecord(String reportId, List<String> ids) {
// 初始化集成报告与用例的关联关系
List<ApiScenarioRecord> records = ids.stream().map(id -> {
ApiScenarioRecord scenarioRecord = new ApiScenarioRecord();
scenarioRecord.setApiScenarioReportId(reportId);
scenarioRecord.setApiScenarioId(id);
return scenarioRecord;
}).toList();
apiScenarioReportService.insertApiScenarioReport(List.of(), records);
}
/**
* 执行串行的下一个任务
*
@ -270,9 +367,11 @@ public class ApiScenarioBatchRunService {
TaskRequestDTO taskRequest = getTaskRequestDTO(apiScenario.getProjectId(), queue.getRunModeConfig());
TaskItem taskItem = apiExecuteService.getTaskItem(reportId, queueDetail.getResourceId());
taskItem.setId(queueDetail.getTaskItemId());
taskRequest.setTaskItem(taskItem);
taskRequest.getTaskInfo().setQueueId(queue.getQueueId());
taskRequest.getTaskInfo().setUserId(queue.getUserId());
taskRequest.getTaskInfo().setTaskId(queue.getTaskId());
apiExecuteService.execute(taskRequest);
}

View File

@ -24,10 +24,12 @@ import io.metersphere.api.service.queue.ApiExecutionSetService;
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
import io.metersphere.project.api.processor.MsProcessor;
import io.metersphere.project.api.processor.TimeWaitingProcessor;
import io.metersphere.project.domain.Project;
import io.metersphere.project.dto.environment.EnvironmentInfoDTO;
import io.metersphere.project.dto.environment.http.HttpConfig;
import io.metersphere.project.dto.environment.http.HttpConfigModuleMatchRule;
import io.metersphere.project.dto.environment.http.SelectModule;
import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.project.service.EnvironmentGroupService;
import io.metersphere.project.service.EnvironmentService;
import io.metersphere.sdk.constants.*;
@ -35,7 +37,10 @@ import io.metersphere.sdk.dto.api.task.*;
import io.metersphere.sdk.util.DateUtils;
import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.LogUtils;
import io.metersphere.system.domain.ExecTask;
import io.metersphere.system.domain.ExecTaskItem;
import io.metersphere.system.service.ApiPluginService;
import io.metersphere.system.service.BaseTaskHubService;
import io.metersphere.system.uid.IDGenerator;
import jakarta.annotation.Resource;
import org.apache.commons.collections.MapUtils;
@ -81,6 +86,10 @@ public class ApiScenarioRunService {
private ApiScenarioBlobMapper apiScenarioBlobMapper;
@Resource
private ApiExecutionSetService apiExecutionSetService;
@Resource
private ProjectMapper projectMapper;
@Resource
private BaseTaskHubService baseTaskHubService;
public TaskRequestDTO run(String id, String reportId, String userId) {
ApiScenarioDetail apiScenarioDetail = getForRun(id);
@ -179,6 +188,23 @@ public class ApiScenarioRunService {
String reportId,
String userId) {
Project project = projectMapper.selectByPrimaryKey(apiScenario.getProjectId());
ExecTask execTask = apiCommonService.newExecTask(project.getId(), userId);
execTask.setCaseCount(1L);
execTask.setTaskName(apiScenario.getName());
execTask.setOrganizationId(project.getOrganizationId());
execTask.setTriggerMode(TaskTriggerMode.MANUAL.name());
execTask.setTaskType(ExecTaskType.API_SCENARIO.name());
ExecTaskItem execTaskItem = apiCommonService.newExecTaskItem(execTask.getId(), project.getId(), userId);
execTaskItem.setOrganizationId(project.getOrganizationId());
execTaskItem.setResourceType(ApiExecuteResourceType.API_SCENARIO.name());
execTaskItem.setResourceId(apiScenario.getId());
execTaskItem.setResourceName(apiScenario.getName());
baseTaskHubService.insertExecTaskAndDetail(execTask, execTaskItem);
msScenario.setResourceId(apiScenario.getId());
// 解析生成场景树并保存临时变量
@ -191,6 +217,8 @@ public class ApiScenarioRunService {
TaskRequestDTO taskRequest = getTaskRequest(reportId, apiScenario.getId(), apiScenario.getProjectId(), ApiExecuteRunMode.RUN.name());
TaskInfo taskInfo = taskRequest.getTaskInfo();
TaskItem taskItem = taskRequest.getTaskItem();
taskItem.setId(execTaskItem.getId());
taskInfo.setTaskId(execTask.getId());
taskInfo.getRunModeConfig().setPoolId(poolId);
taskInfo.setSaveResult(true);
taskInfo.getRunModeConfig().setEnvironmentId(parseParam.getEnvironmentId());
@ -208,6 +236,7 @@ public class ApiScenarioRunService {
ApiScenarioParamConfig parseConfig = getApiScenarioParamConfig(apiScenario.getProjectId(), parseParam, tmpParam.getScenarioParseEnvInfo());
parseConfig.setReportId(reportId);
parseConfig.setTaskItemId(taskItem.getId());
// 初始化报告
ApiScenarioReport scenarioReport = getScenarioReport(userId);
@ -314,6 +343,7 @@ public class ApiScenarioRunService {
ApiScenarioParamConfig parseConfig = getApiScenarioParamConfig(apiScenarioDetail.getProjectId(), parseParam, tmpParam.getScenarioParseEnvInfo());
parseConfig.setReportId(reportId);
parseConfig.setTaskItemId(taskItem.getId());
parseConfig.setRetryOnFail(request.getRunModeConfig().getRetryOnFail());
parseConfig.setRetryConfig(request.getRunModeConfig().getRetryConfig());
@ -380,9 +410,11 @@ public class ApiScenarioRunService {
msScenario.setProjectId(request.getProjectId());
msScenario.setResourceId(request.getId());
List<ApiScenarioCsv> dbCsv = apiScenarioService.getApiScenarioCsv(apiScenario.getId());
List<CsvVariable> csvVariables = apiScenarioService.getCsvVariables(msScenario.getScenarioConfig());
apiScenarioService.handleRefUpgradeFile(csvVariables, dbCsv);
if (!hasSave) {
List<ApiScenarioCsv> dbCsv = apiScenarioService.getApiScenarioCsv(apiScenario.getId());
List<CsvVariable> csvVariables = apiScenarioService.getCsvVariables(msScenario.getScenarioConfig());
apiScenarioService.handleRefUpgradeFile(csvVariables, dbCsv);
}
// 处理特殊的步骤详情
apiScenarioService.addSpecialStepDetails(request.getSteps(), request.getStepDetails());
@ -396,14 +428,16 @@ public class ApiScenarioRunService {
TaskRequestDTO taskRequest = getTaskRequest(request.getReportId(), request.getId(), request.getProjectId(),
apiExecuteService.getDebugRunModule(request.getFrontendDebug()));
TaskInfo taskInfo = taskRequest.getTaskInfo();
taskInfo.setTaskId(request.getReportId());
TaskItem taskItem = taskRequest.getTaskItem();
taskItem.setId(request.getReportId());
taskInfo.setSaveResult(false);
taskInfo.setRealTime(true);
taskItem.setRequestCount(tmpParam.getRequestCount().get());
ApiScenarioParamConfig parseConfig = getApiScenarioParamConfig(request.getProjectId(), request, tmpParam.getScenarioParseEnvInfo());
parseConfig.setReportId(request.getReportId());
parseConfig.setTaskItemId(taskItem.getId());
return apiExecuteService.execute(runRequest, taskRequest, parseConfig);
}
@ -516,13 +550,16 @@ public class ApiScenarioRunService {
}
public ApiScenarioRecord getApiScenarioRecord(ApiScenario apiScenario, ApiScenarioReport scenarioReport) {
return getApiScenarioRecord(apiScenario.getId(), scenarioReport);
}
public ApiScenarioRecord getApiScenarioRecord(String apiScenarioId, ApiScenarioReport scenarioReport) {
ApiScenarioRecord scenarioRecord = new ApiScenarioRecord();
scenarioRecord.setApiScenarioId(apiScenario.getId());
scenarioRecord.setApiScenarioId(apiScenarioId);
scenarioRecord.setApiScenarioReportId(scenarioReport.getId());
return scenarioRecord;
}
public ApiScenarioReport getScenarioReport(String userId) {
ApiScenarioReport scenarioReport = new ApiScenarioReport();
scenarioReport.setId(IDGenerator.nextStr());

View File

@ -1434,12 +1434,6 @@ public class ApiScenarioService extends MoveNodeService {
*/
public Map<String, String> getPartialRefStepDetailMap(List<? extends ApiScenarioStepCommonDTO> steps) {
steps.forEach(step -> {
if (isPartialRef(step)) {
}
});
List<String> needBlobStepIds = steps.stream()
.filter(this::isPartialRef)
.map(ApiScenarioStepCommonDTO::getId)

View File

@ -1,8 +1,6 @@
package io.metersphere.api.controller;
import io.metersphere.api.service.ApiExecuteService;
import io.metersphere.api.service.ApiFileResourceService;
import io.metersphere.api.service.debug.ApiDebugService;
import io.metersphere.sdk.constants.DefaultRepositoryDir;
import io.metersphere.sdk.constants.StorageType;
import io.metersphere.sdk.file.FileCopyRequest;
@ -33,15 +31,10 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
public class ApiExecuteResourceControllerTest extends BaseTest {
private static final String BASE_PATH = "/api/execute/resource/";
private static final String SCRIPT = "script?reportId={0}&testId={1}";
private static final String FILE = "file?reportId={0}&testId={1}";
private static final String FILE = "file?taskItemId={0}";
@Resource
private StringRedisTemplate stringRedisTemplate;
@Resource
private ApiExecuteService apiExecuteService;
@Resource
private ApiDebugService apiDebugService;
@Resource
private ApiFileResourceService apiFileResourceService;
@Override
@ -49,11 +42,6 @@ public class ApiExecuteResourceControllerTest extends BaseTest {
return BASE_PATH;
}
@Test
public void getScript() throws Exception {
this.requestGetWithOk(SCRIPT, "reportId", "testId");
}
@Test
public void downloadFile() throws Exception {
String fileName = IDGenerator.nextStr() + "_file_upload.JPG";
@ -62,18 +50,17 @@ public class ApiExecuteResourceControllerTest extends BaseTest {
FileRequest fileRequest = new FileCopyRequest();
fileRequest.setFileName(fileName);
fileRequest.setFolder(DefaultRepositoryDir.getSystemTempDir() + "/" + fileId);
mockMvc.perform(getPostRequestBuilder(FILE, fileRequest, "reportId", "testId"))
mockMvc.perform(getPostRequestBuilder(FILE, fileRequest, "reportId"))
.andExpect(status().isOk());
String reportId = UUID.randomUUID().toString();
String testId = UUID.randomUUID().toString();
String scriptRedisKey = apiExecuteService.getTaskKey(reportId, testId);
String scriptRedisKey = reportId;
stringRedisTemplate.opsForValue().set(scriptRedisKey, "aaa");
mockMvc.perform(getPostRequestBuilder(FILE, fileRequest, reportId, testId))
mockMvc.perform(getPostRequestBuilder(FILE, fileRequest, reportId))
.andExpect(status().isOk());
fileRequest.setStorage(StorageType.MINIO.name());
mockMvc.perform(getPostRequestBuilder(FILE, fileRequest, reportId, testId))
mockMvc.perform(getPostRequestBuilder(FILE, fileRequest, reportId))
.andExpect(status().isOk());
}

View File

@ -1,8 +1,6 @@
package io.metersphere.system.mapper;
import io.metersphere.system.domain.ExecTaskItem;
import io.metersphere.system.dto.sdk.BasePageRequest;
import io.metersphere.system.dto.taskhub.TaskHubDTO;
import io.metersphere.system.dto.taskhub.TaskHubItemDTO;
import io.metersphere.system.dto.taskhub.request.TaskHubItemRequest;
import org.apache.ibatis.annotations.Param;
@ -18,4 +16,6 @@ public interface ExtExecTaskItemMapper {
List<ExecTaskItem> selectItemByTaskIds(@Param("taskIds") List<String> taskIds, @Param("orgId") String orgId, @Param("projectId") String projectId);
List<ExecTaskItem> selectPoolNodeByIds(@Param("ids") List<String> ids);
List<ExecTaskItem> selectExecInfoByResourceIds(@Param("resourceIds") List<String> resourceIds);
}

View File

@ -33,6 +33,14 @@
</if>
</where>
</select>
<select id="selectExecInfoByResourceIds" resultType="io.metersphere.system.domain.ExecTaskItem">
SELECT id, resource_id
FROM exec_task_item
WHERE resource_id IN
<foreach collection="resourceIds" item="resourceId" open="(" separator="," close=")">
#{resourceId}
</foreach>
</select>
<select id="selectItemByTaskIds" resultType="io.metersphere.system.domain.ExecTaskItem">
select id, task_id, `status`, result

View File

@ -28,6 +28,7 @@ import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
@ -136,22 +137,45 @@ public class BaseTaskHubService {
return extOrganizationMapper.getOrgListByProjectIds(projectIds);
}
/**
* 单任务详情数据入库接口
*
* @param item
*/
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void insertExecTaskAndDetail(ExecTask task, ExecTaskItem item) {
execTaskMapper.insertSelective(task);
execTaskItemMapper.insertSelective(item);
}
/**
* 单任务详情数据入库接口
*
* @param task
*/
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void insertExecTask(ExecTask task) {
execTaskMapper.insertSelective(task);
}
/**
* 单任务详情数据入库接口
*
* @param items
*/
public void insertExecTaskAndDetail(List<ExecTaskItem> items) {
if (CollectionUtils.isNotEmpty(items)) {
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ExecTaskItemMapper itemMapper = sqlSession.getMapper(ExecTaskItemMapper.class);
SubListUtils.dealForSubList(items, 1000, subList -> {
subList.forEach(itemMapper::insertSelective);
});
sqlSession.flushStatements();
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void insertExecTaskDetail(List<ExecTaskItem> items) {
insertExecTaskAndDetail(List.of(), items);
}
/**
* 单任务详情数据入库接口
*
* @param items
*/
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void insertExecTaskAndDetail(ExecTask task, List<ExecTaskItem> items) {
insertExecTaskAndDetail(List.of(task), items);
}
@ -161,6 +185,7 @@ public class BaseTaskHubService {
* @param tasks
* @param items
*/
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void insertExecTaskAndDetail(List<ExecTask> tasks, List<ExecTaskItem> items) {
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
if (CollectionUtils.isNotEmpty(tasks)) {

View File

@ -218,7 +218,6 @@ public class BaseTaskHubControllerTests extends BaseTest {
Assertions.assertNotNull(resultHolder);
}
@Test
@Order(4)
public void getOrgStatistics() throws Exception {
@ -261,10 +260,10 @@ public class BaseTaskHubControllerTests extends BaseTest {
}
@Test
@Order(21)
public void testInsert() throws Exception {
baseTaskHubService.insertExecTaskAndDetail(new ArrayList<>());
ExecTaskItem execTaskItem = new ExecTaskItem();
execTaskItem.setId("1111");
execTaskItem.setTaskId("1");
@ -276,10 +275,9 @@ public class BaseTaskHubControllerTests extends BaseTest {
execTaskItem.setOrganizationId("1234123");
execTaskItem.setExecutor("admin");
execTaskItem.setResourceName("测试");
baseTaskHubService.insertExecTaskAndDetail(List.of(execTaskItem));
baseTaskHubService.insertExecTaskAndDetail(new ArrayList<>(), new ArrayList<>());
execTaskItem.setId("2333");
ExecTask execTask = new ExecTask();
execTask.setId("121321");
@ -293,6 +291,9 @@ public class BaseTaskHubControllerTests extends BaseTest {
execTask.setOrganizationId("123432");
execTask.setCreateTime(System.currentTimeMillis());
execTask.setCreateUser("admin");
baseTaskHubService.insertExecTaskAndDetail(execTask, List.of(execTaskItem));
execTask.setId("121329");
execTaskItem.setId("2333555");
baseTaskHubService.insertExecTaskAndDetail(List.of(execTask), List.of(execTaskItem));
}

View File

@ -0,0 +1,12 @@
package io.metersphere.plan.dto;
import lombok.Data;
@Data
public class TestPlanApiCaseBatchRunDTO {
private String id;
private String name;
private String apiCaseId;
private String environmentId;
private String testPlanCollectionId;
}

View File

@ -1,8 +0,0 @@
package io.metersphere.plan.dto;
import io.metersphere.plan.domain.TestPlanApiCase;
public class TestPlanApiCaseDTO extends TestPlanApiCase {
}

View File

@ -0,0 +1,12 @@
package io.metersphere.plan.dto;
import lombok.Data;
@Data
public class TestPlanApiScenarioBatchRunDTO {
private String id;
private String name;
private String apiScenarioId;
private String environmentId;
private String testPlanCollectionId;
}

View File

@ -41,4 +41,7 @@ public class TestPlanReportGenPreParam {
@Schema(description = "是否手动生成报告")
private Boolean useManual;
@Schema(description = "执行的任务ID")
private String taskId;
}

View File

@ -4,10 +4,7 @@ import io.metersphere.api.dto.definition.ApiDefinitionDTO;
import io.metersphere.functional.dto.FunctionalCaseModuleCountDTO;
import io.metersphere.functional.dto.ProjectOptionDTO;
import io.metersphere.plan.domain.TestPlanApiCase;
import io.metersphere.plan.dto.ApiCaseModuleDTO;
import io.metersphere.plan.dto.ResourceSelectParam;
import io.metersphere.plan.dto.TestPlanCaseRunResultCount;
import io.metersphere.plan.dto.TestPlanResourceExecResultDTO;
import io.metersphere.plan.dto.*;
import io.metersphere.plan.dto.request.TestPlanApiCaseBatchRequest;
import io.metersphere.plan.dto.request.TestPlanApiCaseModuleRequest;
import io.metersphere.plan.dto.request.TestPlanApiCaseRequest;
@ -74,12 +71,15 @@ public interface ExtTestPlanApiCaseMapper {
List<TestPlanApiCase> getApiCaseExecuteInfoByIds(@Param("ids") List<String> ids);
List<TestPlanApiCaseBatchRunDTO> getSelectIdAndCollectionId(@Param("request") TestPlanApiCaseBatchRequest request);
List<TestPlanApiCase> getSelectIdAndCollectionId(@Param("request") TestPlanApiCaseBatchRequest request);
List<TestPlanApiCaseBatchRunDTO> getBatchRunInfoByIds(@Param("ids") List<String> ids);
List<TestPlanApiCase> getPlanApiCaseNotDeletedByCollectionIds(@Param("collectionIds") List<String> collectionIds);
List<TestPlanResourceExecResultDTO> selectDistinctExecResult(String projectId);
List<TestPlanResourceExecResultDTO> selectDistinctExecResultByTestPlanIds(@Param("testPlanIds") List<String> testPlanIds);
Integer countByPlanId(@Param("planId") String planId);
}

View File

@ -238,7 +238,6 @@
and t.test_plan_id = #{request.testPlanId}
<include refid="queryApiCaseWhereCondition"/>
</select>
<select id="selectByTestPlanIdAndNotDeleted" resultType="io.metersphere.plan.domain.TestPlanApiCase">
SELECT t.*
FROM test_plan_api_case t
@ -665,8 +664,8 @@
</foreach>
</select>
<select id="getSelectIdAndCollectionId" resultType="io.metersphere.plan.domain.TestPlanApiCase">
SELECT t.id as id, t.test_plan_collection_id as test_plan_collection_id
<select id="getSelectIdAndCollectionId" resultType="io.metersphere.plan.dto.TestPlanApiCaseBatchRunDTO">
SELECT t.id as id, t.test_plan_collection_id as test_plan_collection_id, atc.name as name, t.environment_id, atc.id as api_case_id
FROM test_plan_api_case t
INNER JOIN api_test_case atc ON t.api_case_id = atc.id
INNER JOIN api_definition a ON atc.api_definition_id = a.id
@ -717,4 +716,20 @@
</foreach>
AND test_plan.status != 'ARCHIVED'
</select>
<select id="getBatchRunInfoByIds" resultType="io.metersphere.plan.dto.TestPlanApiCaseBatchRunDTO">
SELECT id, test_plan_collection_id, environment_id, api_case_id as api_case_id
FROM test_plan_api_case
where
id in
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
<select id="countByPlanId" resultType="java.lang.Integer">
select count(0)
from test_plan_api_case tpac join api_test_case atc on atc.id = tpac.api_case_id
<where>
atc.deleted = false and tpac.test_plan_id = #{planId}
</where>
</select>
</mapper>

View File

@ -3,10 +3,7 @@ package io.metersphere.plan.mapper;
import io.metersphere.functional.dto.FunctionalCaseModuleCountDTO;
import io.metersphere.functional.dto.ProjectOptionDTO;
import io.metersphere.plan.domain.TestPlanApiScenario;
import io.metersphere.plan.dto.ApiScenarioModuleDTO;
import io.metersphere.plan.dto.ResourceSelectParam;
import io.metersphere.plan.dto.TestPlanCaseRunResultCount;
import io.metersphere.plan.dto.TestPlanResourceExecResultDTO;
import io.metersphere.plan.dto.*;
import io.metersphere.plan.dto.request.BasePlanCaseBatchRequest;
import io.metersphere.plan.dto.request.TestPlanApiScenarioBatchRunRequest;
import io.metersphere.plan.dto.request.TestPlanApiScenarioModuleRequest;
@ -68,7 +65,7 @@ public interface ExtTestPlanApiScenarioMapper {
void batchUpdateExecutor(@Param("ids") List<String> ids, @Param("userId") String userId);
List<TestPlanApiScenario> getSelectIdAndCollectionId(@Param("request") TestPlanApiScenarioBatchRunRequest request);
List<TestPlanApiScenarioBatchRunDTO> getSelectIdAndCollectionId(@Param("request") TestPlanApiScenarioBatchRunRequest request);
List<String> getIdsByReportIdAndCollectionId(@Param("testPlanReportId") String testPlanReportId, @Param("collectionId") String collectionId);
@ -77,4 +74,8 @@ public interface ExtTestPlanApiScenarioMapper {
List<TestPlanResourceExecResultDTO> selectDistinctExecResult(String projectId);
List<TestPlanResourceExecResultDTO> selectDistinctExecResultByTestPlanIds(@Param("testPlanIds") List<String> testPlanIds);
List<TestPlanApiScenarioBatchRunDTO> getBatchRunInfoByIds(@Param("ids") List<String> ids);
Integer countByPlanId(@Param("planId") String planId);
}

View File

@ -456,9 +456,12 @@
AND api_scenario.deleted = #{deleted}
<include refid="queryWhereConditionByBatchQueryRequest"/>
</select>
<select id="getSelectIdAndCollectionId" resultType="io.metersphere.plan.domain.TestPlanApiScenario">
<select id="getSelectIdAndCollectionId" resultType="io.metersphere.plan.dto.TestPlanApiScenarioBatchRunDTO">
SELECT
test_plan_api_scenario.id as id, test_plan_api_scenario.test_plan_collection_id as testPlanCollectionId
test_plan_api_scenario.id as id, test_plan_api_scenario.test_plan_collection_id as testPlanCollectionId,
test_plan_api_scenario.environment_id as environmentId,
api_scenario.name as name,
api_scenario.id as apiScenarioId,
FROM
test_plan_api_scenario
INNER JOIN api_scenario on api_scenario.id = test_plan_api_scenario.api_scenario_id
@ -556,6 +559,15 @@
AND test_plan.status != 'ARCHIVED'
</select>
<select id="getBatchRunInfoByIds" resultType="io.metersphere.plan.dto.TestPlanApiScenarioBatchRunDTO">
SELECT id, test_plan_collection_id, environment_id, api_scenario_id
FROM test_plan_api_scenario
where
id in
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
<update id="batchUpdateExecutor">
update test_plan_api_scenario
@ -565,4 +577,12 @@
#{id}
</foreach>
</update>
<select id="countByPlanId" resultType="java.lang.Integer">
select count(0)
from test_plan_api_scenario tpas join api_scenario asce on asce.id = tpas.api_scenario_id
<where>
asce.deleted = false and tpas.test_plan_id = #{planId}
</where>
</select>
</mapper>

View File

@ -28,6 +28,8 @@ import io.metersphere.sdk.dto.queue.TestPlanExecutionQueue;
import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.LogUtils;
import io.metersphere.sdk.util.SubListUtils;
import io.metersphere.system.domain.ExecTaskItem;
import io.metersphere.system.mapper.ExtExecTaskItemMapper;
import io.metersphere.system.uid.IDGenerator;
import jakarta.annotation.Resource;
import jodd.util.StringUtil;
@ -71,6 +73,8 @@ public class PlanRunTestPlanApiCaseService {
private TestPlanApiBatchRunBaseService testPlanApiBatchRunBaseService;
@Resource
private ExtTestPlanReportApiCaseMapper extTestPlanReportApiCaseMapper;
@Resource
private ExtExecTaskItemMapper extExecTaskItemMapper;
/**
* 串行批量执行
@ -89,9 +93,14 @@ public class PlanRunTestPlanApiCaseService {
return true;
}
String queueId = testPlanExecutionQueue.getPrepareReportId() + "_" + collection.getId();
// 先初始化集成报告设置好报告ID再初始化执行队列
ExecutionQueue queue = apiBatchRunBaseService.initExecutionqueue(queueId, ids, runModeConfig, ApiExecuteResourceType.PLAN_RUN_API_CASE.name(), parentQueueId, userId);
ExecutionQueue queue = apiBatchRunBaseService.initExecutionQueue(testPlanExecutionQueue.getTaskId(), runModeConfig, ApiExecuteResourceType.PLAN_RUN_API_CASE.name(), parentQueueId, userId);
SubListUtils.dealForSubList(ids, 100, subIds -> {
List<ExecTaskItem> execTaskItems = extExecTaskItemMapper.selectExecInfoByResourceIds(subIds);
// 初始化队列项
apiBatchRunBaseService.initExecutionQueueDetails(queue.getQueueId(), execTaskItems);
});
// 执行第一个任务
ExecutionQueueDetail nextDetail = apiExecutionQueueService.getNextDetail(queue.getQueueId());
@ -119,12 +128,19 @@ public class PlanRunTestPlanApiCaseService {
}
List<ApiTestCase> apiTestCases = new ArrayList<>(testPlanReportApiCases.size());
Map<String, String> resourceTaskItemMap = new HashMap<>();
List<String> caseIds = testPlanReportApiCases.stream()
.map(TestPlanReportApiCase::getApiCaseId).collect(Collectors.toList());
// 分批查询
SubListUtils.dealForSubList(caseIds, 100, subIds -> apiTestCases.addAll(extApiTestCaseMapper.getApiCaseExecuteInfoByIds(subIds)));
SubListUtils.dealForSubList(testPlanReportApiCases, 100,
subTestPlanReportApiCases-> {
List<String> subIds = subTestPlanReportApiCases.stream().map(TestPlanReportApiCase::getId).toList();
extExecTaskItemMapper.selectExecInfoByResourceIds(subIds)
.forEach(execTaskItem -> resourceTaskItemMap.put(execTaskItem.getResourceId(), execTaskItem.getId()));
});
Map<String, ApiTestCase> apiCaseMap = apiTestCases.stream()
.collect(Collectors.toMap(ApiTestCase::getId, Function.identity()));
@ -146,6 +162,7 @@ public class PlanRunTestPlanApiCaseService {
continue;
}
TaskItem taskItem = apiExecuteService.getTaskItem(reportId, id);
taskItem.setId(resourceTaskItemMap.get(testPlanReportApiCase.getId()));
taskItem.setRequestCount(1L);
taskItems.add(taskItem);
}
@ -158,6 +175,7 @@ public class PlanRunTestPlanApiCaseService {
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(testPlanId);
TaskBatchRequestDTO taskRequest = apiTestCaseBatchRunService.getTaskBatchRequestDTO(testPlan.getProjectId(), runModeConfig);
taskRequest.setTaskItems(taskItems);
taskRequest.getTaskInfo().setTaskId(testPlanExecutionQueue.getTaskId());
taskRequest.getTaskInfo().setParentQueueId(parentQueueId);
taskRequest.getTaskInfo().setUserId(userId);
taskRequest.getTaskInfo().setResourceType(ApiExecuteResourceType.PLAN_RUN_API_CASE.name());
@ -197,11 +215,13 @@ public class PlanRunTestPlanApiCaseService {
// 独立报告执行到当前任务时初始化报告
String reportId = initApiReport(runModeConfig, List.of(testPlanReportApiCase), Map.of(apiTestCase.getId(), apiTestCase), queue.getUserId()).get(resourceId);
TaskRequestDTO taskRequest = testPlanApiCaseBatchRunService.getTaskRequestDTO(reportId, testPlanReportApiCase.getId(), apiTestCase, runModeConfig);
taskRequest.getTaskInfo().setTaskId(queue.getTaskId());
taskRequest.getTaskInfo().setResourceType(ApiExecuteResourceType.PLAN_RUN_API_CASE.name());
taskRequest.getTaskInfo().setQueueId(queue.getQueueId());
taskRequest.getTaskInfo().setUserId(queue.getUserId());
taskRequest.getTaskInfo().setParentQueueId(queue.getParentQueueId());
taskRequest.getTaskItem().setRequestCount(1L);
taskRequest.getTaskItem().setId(queueDetail.getTaskItemId());
apiExecuteService.execute(taskRequest);
}
@ -234,7 +254,7 @@ public class PlanRunTestPlanApiCaseService {
// 创建报告和用例的关联关系
ApiTestCaseRecord apiTestCaseRecord = apiTestCaseService.getApiTestCaseRecord(apiTestCase, apiReport);
apiTestCaseRecords.add(apiTestCaseRecord);
apiReportSteps.add(testPlanApiCaseBatchRunService.getApiReportStep(testPlanReportApiCase.getId(), apiTestCase, apiReport.getId(), 1));
apiReportSteps.add(testPlanApiCaseBatchRunService.getApiReportStep(testPlanReportApiCase.getId(), apiTestCase.getName(), apiReport.getId(), 1));
resourceReportMap.put(testPlanReportApiCase.getId(), apiReport.getId());
}
apiReportService.insertApiReport(apiReports, apiTestCaseRecords);

View File

@ -12,21 +12,22 @@ import io.metersphere.api.service.queue.ApiExecutionQueueService;
import io.metersphere.api.service.queue.ApiExecutionSetService;
import io.metersphere.api.service.scenario.ApiScenarioReportService;
import io.metersphere.api.service.scenario.ApiScenarioRunService;
import io.metersphere.plan.domain.TestPlan;
import io.metersphere.plan.domain.TestPlanCollection;
import io.metersphere.plan.domain.TestPlanReportApiScenario;
import io.metersphere.plan.domain.TestPlanReportApiScenarioExample;
import io.metersphere.plan.domain.*;
import io.metersphere.plan.mapper.ExtTestPlanApiScenarioMapper;
import io.metersphere.plan.mapper.TestPlanMapper;
import io.metersphere.plan.mapper.TestPlanReportApiScenarioMapper;
import io.metersphere.sdk.constants.ApiExecuteResourceType;
import io.metersphere.sdk.constants.TaskTriggerMode;
import io.metersphere.sdk.dto.api.task.*;
import io.metersphere.sdk.dto.queue.ExecutionQueue;
import io.metersphere.sdk.dto.queue.ExecutionQueueDetail;
import io.metersphere.sdk.dto.queue.TestPlanExecutionQueue;
import io.metersphere.sdk.util.DateUtils;
import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.LogUtils;
import io.metersphere.sdk.util.SubListUtils;
import io.metersphere.system.domain.ExecTaskItem;
import io.metersphere.system.mapper.ExtExecTaskItemMapper;
import io.metersphere.system.uid.IDGenerator;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
@ -66,6 +67,8 @@ public class PlanRunTestPlanApiScenarioService {
private ExtApiScenarioMapper extApiScenarioMapper;
@Resource
private ApiScenarioReportService apiScenarioReportService;
@Resource
private ExtExecTaskItemMapper extExecTaskItemMapper;
/**
* 串行批量执行
@ -84,10 +87,15 @@ public class PlanRunTestPlanApiScenarioService {
return true;
}
String queueId = testPlanExecutionQueue.getPrepareReportId() + "_" + collection.getId();
// 先初始化集成报告设置好报告ID再初始化执行队列
ExecutionQueue queue = apiBatchRunBaseService.initExecutionqueue(queueId, ids, runModeConfig, ApiExecuteResourceType.PLAN_RUN_API_SCENARIO.name(), parentQueueId, userId);
ExecutionQueue queue = apiBatchRunBaseService.initExecutionQueue(testPlanExecutionQueue.getTaskId(), runModeConfig, ApiExecuteResourceType.PLAN_RUN_API_SCENARIO.name(), parentQueueId, userId);
SubListUtils.dealForSubList(ids, 100, subIds -> {
List<ExecTaskItem> execTaskItems = extExecTaskItemMapper.selectExecInfoByResourceIds(subIds);
// 初始化队列项
apiBatchRunBaseService.initExecutionQueueDetails(queue.getQueueId(), execTaskItems);
});
// 执行第一个任务
ExecutionQueueDetail nextDetail = apiExecutionQueueService.getNextDetail(queue.getQueueId());
executeNextTask(queue, nextDetail);
@ -109,18 +117,31 @@ public class PlanRunTestPlanApiScenarioService {
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(testPlanId);
ApiRunModeConfigDTO runModeConfig = testPlanApiBatchRunBaseService.getApiRunModeConfig(collection);
TaskBatchRequestDTO taskRequest = testPlanApiScenarioBatchRunService.getTaskBatchRequestDTO(testPlan.getProjectId(), runModeConfig);
taskRequest.getTaskInfo().setTaskId(testPlanExecutionQueue.getTaskId());
taskRequest.getTaskInfo().setParentQueueId(parentQueueId);
taskRequest.getTaskInfo().setUserId(userId);
taskRequest.getTaskInfo().setResourceType(ApiExecuteResourceType.PLAN_RUN_API_SCENARIO.name());
Map<String, String> resourceTaskItemMap = new HashMap<>();
List<TestPlanReportApiScenario> testPlanReportApiScenarios = getTestPlanReportApiScenarios(testPlanReportId, collection);
if (CollectionUtils.isEmpty(testPlanReportApiScenarios)) {
return true;
}
SubListUtils.dealForSubList(testPlanReportApiScenarios, 100,
subTestPlanReportApiCases-> {
List<String> subIds = subTestPlanReportApiCases.stream().map(TestPlanReportApiScenario::getId).toList();
extExecTaskItemMapper.selectExecInfoByResourceIds(subIds)
.forEach(execTaskItem -> resourceTaskItemMap.put(execTaskItem.getResourceId(), execTaskItem.getId()));
});
Map<String, String> scenarioReportMap = initReport(testPlanReportApiScenarios, runModeConfig, userId);
List<TaskItem> taskItems = testPlanReportApiScenarios.stream()
.map(item -> apiExecuteService.getTaskItem(scenarioReportMap.get(item.getId()), item.getId())).toList();
.map(item -> {
TaskItem taskItem = apiExecuteService.getTaskItem(scenarioReportMap.get(item.getId()), item.getId());
taskItem.setId(resourceTaskItemMap.get(item.getId()));
return taskItem;
}).toList();
// 如果有父队列则初始化执行集合以便判断是否执行完毕
apiExecutionSetService.initSet(parentQueueId, testPlanReportApiScenarios.stream().map(TestPlanReportApiScenario::getId).toList());
taskRequest.setTaskItems(taskItems);
@ -150,10 +171,11 @@ public class PlanRunTestPlanApiScenarioService {
List<ApiScenarioReport> apiScenarioReports = new ArrayList<>(testPlanReportApiScenarios.size());
List<ApiScenarioRecord> apiScenarioRecords = new ArrayList<>(testPlanReportApiScenarios.size());
Map<String, String> resourceReportMap = new HashMap<>();
String projectId = "";
for (TestPlanReportApiScenario testPlanReportApiScenario : testPlanReportApiScenarios) {
ApiScenario apiScenario = apiScenarioMap.get(testPlanReportApiScenario.getApiScenarioId());
// 初始化报告
ApiScenarioReport apiScenarioReport = testPlanApiScenarioBatchRunService.getScenarioReport(runModeConfig, apiScenario, userId);
ApiScenarioReport apiScenarioReport = getScenarioReport(runModeConfig, testPlanReportApiScenario, projectId, userId);
apiScenarioReport.setTestPlanScenarioId(testPlanReportApiScenario.getTestPlanApiScenarioId());
// 报告预生成方便停止测试计划时直接更新报告状态
apiScenarioReport.setId(testPlanReportApiScenario.getApiScenarioExecuteReportId());
@ -172,6 +194,19 @@ public class PlanRunTestPlanApiScenarioService {
return resourceReportMap;
}
private ApiScenarioReport getScenarioReport(ApiRunModeConfigDTO runModeConfig, TestPlanReportApiScenario testPlanReportApiScenario, String projectId, String userId) {
ApiScenarioReport apiScenarioReport = apiScenarioRunService.getScenarioReport(userId);
apiScenarioReport.setName(testPlanReportApiScenario.getApiScenarioName() + "_" + DateUtils.getTimeString(System.currentTimeMillis()));
apiScenarioReport.setProjectId(projectId);
apiScenarioReport.setEnvironmentId(runModeConfig.getEnvironmentId());
apiScenarioReport.setRunMode(runModeConfig.getRunMode());
apiScenarioReport.setPoolId(runModeConfig.getPoolId());
apiScenarioReport.setTriggerMode(TaskTriggerMode.BATCH.name());
apiScenarioReport.setTestPlanScenarioId(testPlanReportApiScenario.getId());
apiScenarioReport.setEnvironmentId(apiBatchRunBaseService.getEnvId(runModeConfig, testPlanReportApiScenario.getEnvironmentId()));
return apiScenarioReport;
}
private List<TestPlanReportApiScenario> getTestPlanReportApiScenarios(String testPlanReportId, TestPlanCollection collection) {
TestPlanReportApiScenarioExample example = new TestPlanReportApiScenarioExample();
example.createCriteria()
@ -205,7 +240,9 @@ public class PlanRunTestPlanApiScenarioService {
String reportId = initScenarioReport(runModeConfig, List.of(testPlanReportApiScenario), Map.of(apiScenario.getId(), apiScenario), queue.getUserId()).get(resourceId);
TaskRequestDTO taskRequest = testPlanApiScenarioBatchRunService.getTaskRequestDTO(apiScenario.getProjectId(), queue.getRunModeConfig());
TaskItem taskItem = apiExecuteService.getTaskItem(reportId, queueDetail.getResourceId());
taskItem.setId(queueDetail.getTaskItemId());
taskRequest.setTaskItem(taskItem);
taskRequest.getTaskInfo().setTaskId(queue.getTaskId());
taskRequest.getTaskInfo().setQueueId(queue.getQueueId());
taskRequest.getTaskInfo().setUserId(queue.getUserId());
taskRequest.getTaskInfo().setParentQueueId(queue.getParentQueueId());

View File

@ -7,6 +7,7 @@ import io.metersphere.api.domain.ApiTestCaseRecord;
import io.metersphere.api.mapper.ApiTestCaseMapper;
import io.metersphere.api.mapper.ExtApiTestCaseMapper;
import io.metersphere.api.service.ApiBatchRunBaseService;
import io.metersphere.api.service.ApiCommonService;
import io.metersphere.api.service.ApiExecuteService;
import io.metersphere.api.service.definition.ApiReportService;
import io.metersphere.api.service.definition.ApiTestCaseBatchRunService;
@ -17,20 +18,24 @@ import io.metersphere.plan.domain.TestPlan;
import io.metersphere.plan.domain.TestPlanApiCase;
import io.metersphere.plan.domain.TestPlanCollection;
import io.metersphere.plan.domain.TestPlanCollectionExample;
import io.metersphere.plan.dto.TestPlanApiCaseBatchRunDTO;
import io.metersphere.plan.dto.request.ApiExecutionMapService;
import io.metersphere.plan.dto.request.TestPlanApiCaseBatchRequest;
import io.metersphere.plan.dto.request.TestPlanApiCaseBatchRunRequest;
import io.metersphere.plan.mapper.*;
import io.metersphere.sdk.constants.ApiExecuteResourceType;
import io.metersphere.sdk.constants.CaseType;
import io.metersphere.sdk.constants.CommonConstants;
import io.metersphere.project.domain.Project;
import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.sdk.constants.*;
import io.metersphere.sdk.dto.api.task.*;
import io.metersphere.sdk.dto.queue.ExecutionQueue;
import io.metersphere.sdk.dto.queue.ExecutionQueueDetail;
import io.metersphere.sdk.util.CommonBeanFactory;
import io.metersphere.sdk.util.LogUtils;
import io.metersphere.sdk.util.SubListUtils;
import io.metersphere.sdk.util.*;
import io.metersphere.system.domain.ExecTask;
import io.metersphere.system.domain.ExecTaskItem;
import io.metersphere.system.service.BaseTaskHubService;
import jakarta.annotation.Resource;
import jodd.util.StringUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -51,8 +56,6 @@ public class TestPlanApiCaseBatchRunService {
@Resource
private ExtTestPlanApiCaseMapper extTestPlanApiCaseMapper;
@Resource
private TestPlanApiCaseService testPlanApiCaseService;
@Resource
private TestPlanCollectionMapper testPlanCollectionMapper;
@Resource
private ApiExecuteService apiExecuteService;
@ -75,7 +78,11 @@ public class TestPlanApiCaseBatchRunService {
@Resource
private TestPlanMapper testPlanMapper;
@Resource
private ExtTestPlanMapper extTestPlanMapper;
private ProjectMapper projectMapper;
@Resource
private ApiCommonService apiCommonService;
@Resource
private BaseTaskHubService baseTaskHubService;
/**
* 异步批量执行
@ -97,9 +104,9 @@ public class TestPlanApiCaseBatchRunService {
*/
private void batchRun(TestPlanApiCaseBatchRunRequest request, String userId) {
try {
List<TestPlanApiCase> testPlanApiCases = testPlanApiCaseService.getSelectIdAndCollectionId(request);
List<TestPlanApiCaseBatchRunDTO> testPlanApiCases = getSelectIdAndCollectionId(request);
// 按照 testPlanCollectionId 分组, value 为测试计划用例 ID 列表
Map<String, List<String>> collectionMap = getCollectionMap(testPlanApiCases);
Map<String, List<TestPlanApiCaseBatchRunDTO>> collectionMap = getCollectionMap(testPlanApiCases);
List<TestPlanCollection> testPlanCollections = getTestPlanCollections(request.getTestPlanId());
Iterator<TestPlanCollection> iterator = testPlanCollections.iterator();
@ -122,18 +129,19 @@ public class TestPlanApiCaseBatchRunService {
.collect(Collectors.toList());
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(request.getTestPlanId());
Project project = projectMapper.selectByPrimaryKey(testPlan.getProjectId());
if (apiBatchRunBaseService.isParallel(rootCollection.getExecuteMethod())) {
// 并行执行测试集
for (TestPlanCollection collection : testPlanCollections) {
List<String> ids = collectionMap.get(collection.getId());
List<TestPlanApiCaseBatchRunDTO> collectionCases = collectionMap.get(collection.getId());
ApiRunModeConfigDTO runModeConfig = testPlanApiBatchRunBaseService.getApiRunModeConfig(rootCollection, collection);
if (apiBatchRunBaseService.isParallel(runModeConfig.getRunMode())) {
// 并行执行测试集中的用例
parallelExecute(ids, runModeConfig, null, testPlan.getProjectId(), userId);
parallelExecute(collectionCases, runModeConfig, null, project, userId);
} else {
// 串行执行测试集中的用例
serialExecute(ids, runModeConfig, null, userId);
serialExecute(collectionCases, runModeConfig, null, project, userId);
}
}
} else {
@ -142,8 +150,12 @@ public class TestPlanApiCaseBatchRunService {
// 生成测试集队列
ExecutionQueue collectionQueue = apiBatchRunBaseService.initExecutionqueue(serialCollectionIds,
ApiExecuteResourceType.TEST_PLAN_API_CASE.name(), userId);
Map<String, List<String>> collectionIdMap = collectionMap.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().stream().map(TestPlanApiCaseBatchRunDTO::getId).toList()));
// 记录各测试集中要执行的用例
apiExecutionMapService.initMap(collectionQueue.getQueueId(), collectionMap);
apiExecutionMapService.initMap(collectionQueue.getQueueId(), collectionIdMap);
executeNextCollection(collectionQueue.getQueueId());
}
@ -163,14 +175,17 @@ public class TestPlanApiCaseBatchRunService {
ExecutionQueueDetail nextDetail = apiExecutionQueueService.getNextDetail(queueId);
String collectionId = nextDetail.getResourceId();
List<String> ids = apiExecutionMapService.getAndRemove(queueId, collectionId);
List<TestPlanApiCaseBatchRunDTO> testPlanApiCases = getBatchRunInfo(ids);
TestPlanCollection collection = testPlanCollectionMapper.selectByPrimaryKey(collectionId);
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(collection.getTestPlanId());
Project project = projectMapper.selectByPrimaryKey(testPlan.getProjectId());
ApiRunModeConfigDTO runModeConfig = testPlanApiBatchRunBaseService.getApiRunModeConfig(collection);
if (apiBatchRunBaseService.isParallel(runModeConfig.getRunMode())) {
String testPlanId = collection.getTestPlanId();
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(testPlanId);
parallelExecute(ids, runModeConfig, queueId, testPlan.getProjectId(), userId);
parallelExecute(testPlanApiCases, runModeConfig, queueId, project, userId);
} else {
serialExecute(ids, runModeConfig, queueId, userId);
serialExecute(testPlanApiCases, runModeConfig, queueId, project, userId);
}
}
@ -178,14 +193,9 @@ public class TestPlanApiCaseBatchRunService {
apiExecutionQueueService.deleteQueue(collectionQueueId);
}
private Map<String, List<String>> getCollectionMap(List<TestPlanApiCase> testPlanApiCases) {
Map<String, List<String>> collectionMap = new HashMap<>();
for (TestPlanApiCase testPlanApiCase : testPlanApiCases) {
collectionMap.putIfAbsent(testPlanApiCase.getTestPlanCollectionId(), new ArrayList<>());
List<String> ids = collectionMap.get(testPlanApiCase.getTestPlanCollectionId());
ids.add(testPlanApiCase.getId());
}
return collectionMap;
private Map<String, List<TestPlanApiCaseBatchRunDTO>> getCollectionMap(List<TestPlanApiCaseBatchRunDTO> testPlanApiCases) {
return testPlanApiCases.stream()
.collect(Collectors.groupingBy(TestPlanApiCaseBatchRunDTO::getTestPlanCollectionId));
}
private List<TestPlanCollection> getTestPlanCollections(String testPlanId) {
@ -200,9 +210,16 @@ public class TestPlanApiCaseBatchRunService {
* 串行批量执行
*
*/
public void serialExecute(List<String> ids, ApiRunModeConfigDTO runModeConfig, String parentQueueId, String userId) {
public void serialExecute(List<TestPlanApiCaseBatchRunDTO> testPlanApiCases, ApiRunModeConfigDTO runModeConfig, String parentQueueId, Project project, String userId) {
// 初始化任务
ExecTask execTask = initExecTask(testPlanApiCases.size(), runModeConfig, project, userId);
// 初始化任务项
List<ExecTaskItem> execTaskItems = initExecTaskItem(testPlanApiCases, userId, project, execTask);
// 先初始化集成报告设置好报告ID再初始化执行队列
ExecutionQueue queue = apiBatchRunBaseService.initExecutionqueue(ids, runModeConfig, ApiExecuteResourceType.TEST_PLAN_API_CASE.name(), parentQueueId, userId);
ExecutionQueue queue = apiBatchRunBaseService.initExecutionQueue(execTask.getId(), runModeConfig, ApiExecuteResourceType.TEST_PLAN_API_CASE.name(), parentQueueId, userId);
// 初始化队列项
apiBatchRunBaseService.initExecutionQueueDetails(queue.getQueueId(), execTaskItems);
// 执行第一个任务
ExecutionQueueDetail nextDetail = apiExecutionQueueService.getNextDetail(queue.getQueueId());
@ -214,61 +231,121 @@ public class TestPlanApiCaseBatchRunService {
* 并行批量执行
*
*/
public void parallelExecute(List<String> ids, ApiRunModeConfigDTO runModeConfig, String parentQueueId, String projectId, String userId) {
List<TestPlanApiCase> testPlanApiCases = new ArrayList<>(ids.size());
List<ApiTestCase> apiTestCases = new ArrayList<>(ids.size());
// 分批查询
SubListUtils.dealForSubList(ids, 100, subIds -> testPlanApiCases.addAll(extTestPlanApiCaseMapper.getApiCaseExecuteInfoByIds(subIds)));
List<String> caseIds = testPlanApiCases.stream()
.map(TestPlanApiCase::getApiCaseId).collect(Collectors.toList());
// 分批查询
SubListUtils.dealForSubList(caseIds, 100, subIds -> apiTestCases.addAll(extApiTestCaseMapper.getApiCaseExecuteInfoByIds(subIds)));
Map<String, ApiTestCase> apiCaseMap = apiTestCases.stream()
.collect(Collectors.toMap(ApiTestCase::getId, Function.identity()));
public void parallelExecute(List<TestPlanApiCaseBatchRunDTO> testPlanApiCases, ApiRunModeConfigDTO runModeConfig, String parentQueueId, Project project, String userId) {
// 初始化报告返回用例和报告的 map
Map<String, String> caseReportMap = initApiReport(runModeConfig, testPlanApiCases, apiCaseMap, userId);
Map<String, String> caseReportMap = initApiReport(runModeConfig, testPlanApiCases, project.getId(), userId);
List<TaskItem> taskItems = new ArrayList<>(ids.size());
List<TaskItem> taskItems = new ArrayList<>(testPlanApiCases.size());
// 初始化任务
ExecTask execTask = initExecTask(testPlanApiCases.size(), runModeConfig, project, userId);
// 初始化任务项
Map<String, String> resourceExecTaskItemMap = initExecTaskItem(testPlanApiCases, userId, project, execTask)
.stream()
.collect(Collectors.toMap(ExecTaskItem::getResourceId, ExecTaskItem::getId));
// 这里ID顺序和队列的ID顺序保持一致
Iterator<String> iterator = ids.iterator();
Iterator<TestPlanApiCaseBatchRunDTO> iterator = testPlanApiCases.iterator();
while (iterator.hasNext()) {
String id = iterator.next();
String reportId = caseReportMap.get(id);
TestPlanApiCaseBatchRunDTO testPlanApiCase = iterator.next();
String reportId = caseReportMap.get(testPlanApiCase.getId());
if (StringUtil.isBlank(reportId)) {
iterator.remove();
continue;
}
TaskItem taskItem = apiExecuteService.getTaskItem(reportId, id);
TaskItem taskItem = apiExecuteService.getTaskItem(reportId, testPlanApiCase.getId());
taskItem.setRequestCount(1L);
taskItem.setId(resourceExecTaskItemMap.get(testPlanApiCase.getId()));
taskItems.add(taskItem);
}
if (StringUtils.isNotBlank(parentQueueId)) {
// 如果有父队列则初始化执行集合以便判断是否执行完毕
apiExecutionSetService.initSet(parentQueueId, ids);
apiExecutionSetService.initSet(parentQueueId, testPlanApiCases.stream().map(TestPlanApiCaseBatchRunDTO::getId).toList());
}
TaskBatchRequestDTO taskRequest = getTaskBatchRequestDTO(projectId, runModeConfig);
TaskBatchRequestDTO taskRequest = getTaskBatchRequestDTO(project.getId(), runModeConfig);
taskRequest.setTaskItems(taskItems);
taskRequest.getTaskInfo().setTaskId(execTask.getId());
taskRequest.getTaskInfo().setParentQueueId(parentQueueId);
taskRequest.getTaskInfo().setUserId(userId);
apiExecuteService.batchExecute(taskRequest);
}
public ApiReportStep getApiReportStep(String resourceId, ApiTestCase apiTestCase, String reportId, long sort) {
private ExecTask initExecTask(int caseSize, ApiRunModeConfigDTO runModeConfig, Project project, String userId) {
ExecTask execTask = apiCommonService.newExecTask(project.getId(), userId);
execTask.setCaseCount(Long.valueOf(caseSize));
if (runModeConfig.isIntegratedReport()) {
execTask.setTaskName(runModeConfig.getCollectionReport().getReportName());
} else {
execTask.setTaskName(Translator.get("api_batch_task_name"));
}
execTask.setOrganizationId(project.getOrganizationId());
execTask.setTriggerMode(TaskTriggerMode.MANUAL.name());
execTask.setTaskType(ExecTaskType.TEST_PLAN_API_CASE.name());
baseTaskHubService.insertExecTask(execTask);
return execTask;
}
public List<TestPlanApiCaseBatchRunDTO> getSelectIdAndCollectionId(TestPlanApiCaseBatchRequest request) {
if (request.isSelectAll()) {
List<TestPlanApiCaseBatchRunDTO> testPlanApiCases = extTestPlanApiCaseMapper.getSelectIdAndCollectionId(request);
if (CollectionUtils.isNotEmpty(request.getExcludeIds())) {
testPlanApiCases.removeAll(request.getExcludeIds());
}
return testPlanApiCases;
} else {
return getBatchRunInfo(request.getSelectIds());
}
}
private List<TestPlanApiCaseBatchRunDTO> getBatchRunInfo(List<String> ids) {
List<TestPlanApiCaseBatchRunDTO> testPlanApiCases = new ArrayList<>();
SubListUtils.dealForSubList(ids, 200, (subIds) -> testPlanApiCases.addAll(extTestPlanApiCaseMapper.getBatchRunInfoByIds(subIds)));
// 查询用例名称信息
List<String> caseIds = testPlanApiCases.stream().map(TestPlanApiCaseBatchRunDTO::getApiCaseId).collect(Collectors.toList());
Map<String, String> apiTestCaseNameMap = extApiTestCaseMapper.getNameInfo(caseIds)
.stream()
.collect(Collectors.toMap(ApiTestCase::getId, ApiTestCase::getName));
Map<String, TestPlanApiCaseBatchRunDTO> testPlanApiCaseMap = testPlanApiCases
.stream()
.collect(Collectors.toMap(TestPlanApiCaseBatchRunDTO::getId, Function.identity()));
testPlanApiCases.clear();
// 按ID的顺序排序
for (String id : ids) {
TestPlanApiCaseBatchRunDTO testPlanApiCase = testPlanApiCaseMap.get(id);
if (testPlanApiCase != null) {
testPlanApiCase.setName(apiTestCaseNameMap.get(testPlanApiCase.getApiCaseId()));
testPlanApiCases.add(testPlanApiCase);
}
}
return testPlanApiCases;
}
private List<ExecTaskItem> initExecTaskItem(List<TestPlanApiCaseBatchRunDTO> apiTestCases, String userId, Project project, ExecTask execTask) {
List<ExecTaskItem> execTaskItems = new ArrayList<>(apiTestCases.size());
for (TestPlanApiCaseBatchRunDTO apiTestCase : apiTestCases) {
ExecTaskItem execTaskItem = apiCommonService.newExecTaskItem(execTask.getId(), project.getId(), userId);
execTaskItem.setOrganizationId(project.getOrganizationId());
execTaskItem.setResourceType(ApiExecuteResourceType.TEST_PLAN_API_CASE.name());
execTaskItem.setResourceId(apiTestCase.getId());
execTaskItem.setResourceName(apiTestCase.getName());
execTaskItems.add(execTaskItem);
}
baseTaskHubService.insertExecTaskDetail(execTaskItems);
return execTaskItems;
}
public ApiReportStep getApiReportStep(String resourceId, String name, String reportId, long sort) {
ApiReportStep apiReportStep = new ApiReportStep();
apiReportStep.setReportId(reportId);
apiReportStep.setStepId(resourceId);
apiReportStep.setSort(sort);
apiReportStep.setName(apiTestCase.getName());
apiReportStep.setName(name);
apiReportStep.setStepType(ApiExecuteResourceType.API_CASE.name());
return apiReportStep;
}
@ -291,13 +368,18 @@ public class TestPlanApiCaseBatchRunService {
}
ApiTestCase apiTestCase = apiTestCaseMapper.selectByPrimaryKey(testPlanApiCase.getApiCaseId());
String testPlanId = testPlanApiCase.getTestPlanId();
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(testPlanId);
// 独立报告执行到当前任务时初始化报告
String reportId = initApiReport(runModeConfig, List.of(testPlanApiCase), Map.of(apiTestCase.getId(), apiTestCase), queue.getUserId()).get(testPlanApiCase.getId());
String reportId = initApiReport(runModeConfig, List.of(BeanUtils.copyBean(new TestPlanApiCaseBatchRunDTO(), testPlanApiCase)),
testPlan.getProjectId(), queue.getUserId()).get(testPlanApiCase.getId());
TaskRequestDTO taskRequest = getTaskRequestDTO(reportId, testPlanApiCase.getId(), apiTestCase, runModeConfig);
taskRequest.getTaskInfo().setTaskId(queue.getTaskId());
taskRequest.getTaskInfo().setQueueId(queue.getQueueId());
taskRequest.getTaskInfo().setParentQueueId(queue.getParentQueueId());
taskRequest.getTaskInfo().setUserId(queue.getUserId());
taskRequest.getTaskItem().setId(queueDetail.getTaskItemId());
taskRequest.getTaskItem().setRequestCount(1L);
apiExecuteService.execute(taskRequest);
@ -331,22 +413,21 @@ public class TestPlanApiCaseBatchRunService {
* @param runModeConfig
* @return
*/
public Map<String, String> initApiReport(ApiRunModeConfigDTO runModeConfig, List<TestPlanApiCase> testPlanApiCases,
Map<String, ApiTestCase> caseMap, String userId) {
public Map<String, String> initApiReport(ApiRunModeConfigDTO runModeConfig, List<TestPlanApiCaseBatchRunDTO> testPlanApiCases,
String projectId, String userId) {
List<ApiReport> apiReports = new ArrayList<>();
List<ApiTestCaseRecord> apiTestCaseRecords = new ArrayList<>();
List<ApiReportStep> apiReportSteps = new ArrayList<>();
Map<String, String> resourceReportMap = new HashMap<>();
for (TestPlanApiCase testPlanApiCase : testPlanApiCases) {
ApiTestCase apiTestCase = caseMap.get(testPlanApiCase.getApiCaseId());
for (TestPlanApiCaseBatchRunDTO testPlanApiCase : testPlanApiCases) {
// 初始化报告
ApiReport apiReport = getApiReport(runModeConfig, testPlanApiCase, apiTestCase, userId);
ApiReport apiReport = getApiReport(runModeConfig, testPlanApiCase, projectId, userId);
apiReports.add(apiReport);
// 创建报告和用例的关联关系
ApiTestCaseRecord apiTestCaseRecord = apiTestCaseService.getApiTestCaseRecord(apiTestCase, apiReport);
ApiTestCaseRecord apiTestCaseRecord = apiTestCaseService.getApiTestCaseRecord(testPlanApiCase.getApiCaseId(), apiReport);
apiTestCaseRecords.add(apiTestCaseRecord);
apiReportSteps.add(getApiReportStep(testPlanApiCase.getId(), apiTestCase, apiReport.getId(), 1));
apiReportSteps.add(getApiReportStep(testPlanApiCase.getId(), testPlanApiCase.getName(), apiReport.getId(), 1));
resourceReportMap.put(testPlanApiCase.getId(), apiReport.getId());
}
apiReportService.insertApiReport(apiReports, apiTestCaseRecords);
@ -354,9 +435,12 @@ public class TestPlanApiCaseBatchRunService {
return resourceReportMap;
}
private ApiReport getApiReport(ApiRunModeConfigDTO runModeConfig, TestPlanApiCase testPlanApiCase, ApiTestCase apiTestCase, String userId) {
ApiReport apiReport = apiTestCaseBatchRunService.getApiReport(runModeConfig, apiTestCase, userId);
apiReport.setEnvironmentId(apiBatchRunBaseService.getEnvId(runModeConfig, testPlanApiCase.getEnvironmentId()));
private ApiReport getApiReport(ApiRunModeConfigDTO runModeConfig, TestPlanApiCaseBatchRunDTO testPlanApiCase, String projectId, String userId) {
ApiReport apiReport = apiTestCaseBatchRunService.getApiReport(runModeConfig, userId);
apiReport.setEnvironmentId(apiTestCaseService.getEnvId(runModeConfig, testPlanApiCase.getEnvironmentId()));
apiReport.setName(testPlanApiCase.getName() + "_" + DateUtils.getTimeString(System.currentTimeMillis()));
apiReport.setProjectId(projectId);
apiReport.setTriggerMode(TaskTriggerMode.BATCH.name());
apiReport.setTestPlanCaseId(testPlanApiCase.getId());
return apiReport;
}

View File

@ -10,6 +10,7 @@ import io.metersphere.api.mapper.ApiTestCaseMapper;
import io.metersphere.api.mapper.ExtApiDefinitionModuleMapper;
import io.metersphere.api.mapper.ExtApiTestCaseMapper;
import io.metersphere.api.service.ApiBatchRunBaseService;
import io.metersphere.api.service.ApiCommonService;
import io.metersphere.api.service.ApiExecuteService;
import io.metersphere.api.service.definition.ApiDefinitionModuleService;
import io.metersphere.api.service.definition.ApiDefinitionService;
@ -45,6 +46,8 @@ import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.CommonBeanFactory;
import io.metersphere.sdk.util.SubListUtils;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.domain.ExecTask;
import io.metersphere.system.domain.ExecTaskItem;
import io.metersphere.system.dto.LogInsertModule;
import io.metersphere.system.dto.ModuleSelectDTO;
import io.metersphere.system.dto.sdk.BaseTreeNode;
@ -122,6 +125,8 @@ public class TestPlanApiCaseService extends TestPlanResourceService {
private static final String DEBUG_MODULE_COUNT_ALL = "all";
@Resource
private ExtApiTestCaseMapper extApiTestCaseMapper;
@Resource
private ApiCommonService apiCommonService;
private static final String EXECUTOR = "executeUserName";
@ -557,32 +562,6 @@ public class TestPlanApiCaseService extends TestPlanResourceService {
}
}
public List<TestPlanApiCase> getSelectIdAndCollectionId(TestPlanApiCaseBatchRequest request) {
if (request.isSelectAll()) {
List<TestPlanApiCase> testPlanApiCases = extTestPlanApiCaseMapper.getSelectIdAndCollectionId(request);
if (CollectionUtils.isNotEmpty(request.getExcludeIds())) {
testPlanApiCases.removeAll(request.getExcludeIds());
}
return testPlanApiCases;
} else {
TestPlanApiCaseExample example = new TestPlanApiCaseExample();
example.createCriteria().andIdIn(request.getSelectIds());
Map<String, TestPlanApiCase> testPlanApiCaseMap = testPlanApiCaseMapper.selectByExample(example)
.stream()
.collect(Collectors.toMap(TestPlanApiCase::getId, Function.identity()));
List<TestPlanApiCase> testPlanApiCases = new ArrayList<>(request.getSelectIds().size());
// 按ID的顺序排序
for (String id : request.getSelectIds()) {
TestPlanApiCase testPlanApiCase = testPlanApiCaseMap.get(id);
if (testPlanApiCase != null) {
testPlanApiCases.add(testPlanApiCase);
}
}
return testPlanApiCases;
}
}
/**
* 批量更新执行人
*
@ -772,12 +751,30 @@ public class TestPlanApiCaseService extends TestPlanResourceService {
runModeConfig.setEnvironmentId(apiBatchRunBaseService.getEnvId(runModeConfig, testPlanApiCase.getEnvironmentId()));
runModeConfig.setRunMode(ApiBatchRunMode.PARALLEL.name());
TaskRequestDTO taskRequest = getTaskRequest(reportId, id, apiTestCase.getProjectId(), ApiExecuteRunMode.RUN.name());
Project project = projectMapper.selectByPrimaryKey(apiTestCase.getProjectId());
ExecTask execTask = apiCommonService.newExecTask(project.getId(), userId);
execTask.setCaseCount(1L);
execTask.setTaskName(apiTestCase.getName());
execTask.setOrganizationId(project.getOrganizationId());
execTask.setTriggerMode(TaskTriggerMode.MANUAL.name());
execTask.setTaskType(ExecTaskType.TEST_PLAN_API_CASE.name());
ExecTaskItem execTaskItem = apiCommonService.newExecTaskItem(execTask.getId(), project.getId(), userId);
execTaskItem.setOrganizationId(project.getOrganizationId());
execTaskItem.setResourceType(ApiExecuteResourceType.TEST_PLAN_API_CASE.name());
execTaskItem.setResourceId(apiTestCase.getId());
execTaskItem.setResourceName(apiTestCase.getName());
TaskInfo taskInfo = taskRequest.getTaskInfo();
TaskItem taskItem = taskRequest.getTaskItem();
taskInfo.setTaskId(execTask.getId());
taskInfo.setRunModeConfig(runModeConfig);
taskInfo.setSaveResult(true);
taskInfo.setRealTime(true);
taskInfo.setUserId(userId);
taskItem.setId(execTaskItem.getId());
if (StringUtils.isEmpty(taskItem.getReportId())) {
taskInfo.setRealTime(false);

View File

@ -6,6 +6,7 @@ import io.metersphere.api.domain.ApiScenarioReport;
import io.metersphere.api.mapper.ApiScenarioMapper;
import io.metersphere.api.mapper.ExtApiScenarioMapper;
import io.metersphere.api.service.ApiBatchRunBaseService;
import io.metersphere.api.service.ApiCommonService;
import io.metersphere.api.service.ApiExecuteService;
import io.metersphere.api.service.queue.ApiExecutionQueueService;
import io.metersphere.api.service.scenario.ApiScenarioBatchRunService;
@ -15,22 +16,23 @@ import io.metersphere.plan.domain.TestPlan;
import io.metersphere.plan.domain.TestPlanApiScenario;
import io.metersphere.plan.domain.TestPlanCollection;
import io.metersphere.plan.domain.TestPlanCollectionExample;
import io.metersphere.plan.dto.TestPlanApiScenarioBatchRunDTO;
import io.metersphere.plan.dto.request.ApiExecutionMapService;
import io.metersphere.plan.dto.request.TestPlanApiScenarioBatchRunRequest;
import io.metersphere.plan.mapper.*;
import io.metersphere.sdk.constants.ApiExecuteResourceType;
import io.metersphere.sdk.constants.CaseType;
import io.metersphere.sdk.constants.CommonConstants;
import io.metersphere.sdk.constants.TaskTriggerMode;
import io.metersphere.project.domain.Project;
import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.sdk.constants.*;
import io.metersphere.sdk.dto.api.task.*;
import io.metersphere.sdk.dto.queue.ExecutionQueue;
import io.metersphere.sdk.dto.queue.ExecutionQueueDetail;
import io.metersphere.sdk.util.CommonBeanFactory;
import io.metersphere.sdk.util.DateUtils;
import io.metersphere.sdk.util.LogUtils;
import io.metersphere.sdk.util.SubListUtils;
import io.metersphere.sdk.util.*;
import io.metersphere.system.domain.ExecTask;
import io.metersphere.system.domain.ExecTaskItem;
import io.metersphere.system.service.BaseTaskHubService;
import io.metersphere.system.uid.IDGenerator;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -43,8 +45,6 @@ import java.util.stream.Collectors;
@Service
@Transactional(rollbackFor = Exception.class)
public class TestPlanApiScenarioBatchRunService {
@Resource
private TestPlanApiScenarioService testPlanApiScenarioService;
@Resource
private ApiExecuteService apiExecuteService;
@Resource
@ -68,6 +68,8 @@ public class TestPlanApiScenarioBatchRunService {
@Resource
private TestPlanMapper testPlanMapper;
@Resource
private ProjectMapper projectMapper;
@Resource
private TestPlanApiBatchRunBaseService testPlanApiBatchRunBaseService;
@Resource
private ApiExecutionMapService apiExecutionMapService;
@ -75,6 +77,10 @@ public class TestPlanApiScenarioBatchRunService {
private TestPlanCollectionMapper testPlanCollectionMapper;
@Resource
private ExtTestPlanMapper extTestPlanMapper;
@Resource
private ApiCommonService apiCommonService;
@Resource
private BaseTaskHubService baseTaskHubService;
/**
* 异步批量执行
@ -96,9 +102,9 @@ public class TestPlanApiScenarioBatchRunService {
*/
private void batchRun(TestPlanApiScenarioBatchRunRequest request, String userId) {
try {
List<TestPlanApiScenario> testPlanApiCases = testPlanApiScenarioService.getSelectIdAndCollectionId(request);
List<TestPlanApiScenarioBatchRunDTO> testPlanApiScenarios = getSelectIdAndCollectionId(request);
// 按照 testPlanCollectionId 分组, value 为测试计划用例 ID 列表
Map<String, List<String>> collectionMap = getCollectionMap(testPlanApiCases);
Map<String, List<TestPlanApiScenarioBatchRunDTO>> collectionMap = getCollectionMap(testPlanApiScenarios);
List<TestPlanCollection> testPlanCollections = getTestPlanCollections(request.getTestPlanId());
Iterator<TestPlanCollection> iterator = testPlanCollections.iterator();
@ -121,18 +127,19 @@ public class TestPlanApiScenarioBatchRunService {
.collect(Collectors.toList());
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(request.getTestPlanId());
Project project = projectMapper.selectByPrimaryKey(testPlan.getProjectId());
if (apiBatchRunBaseService.isParallel(rootCollection.getExecuteMethod())) {
// 并行执行测试集
for (TestPlanCollection collection : testPlanCollections) {
List<String> ids = collectionMap.get(collection.getId());
List<TestPlanApiScenarioBatchRunDTO> collectionCases = collectionMap.get(collection.getId());
ApiRunModeConfigDTO runModeConfig = testPlanApiBatchRunBaseService.getApiRunModeConfig(rootCollection, collection);
if (apiBatchRunBaseService.isParallel(runModeConfig.getRunMode())) {
// 并行执行测试集中的用例
parallelExecute(ids, runModeConfig, testPlan.getProjectId(), null, userId);
parallelExecute(collectionCases, runModeConfig, null, project, userId);
} else {
// 串行执行测试集中的用例
serialExecute(ids, runModeConfig, null, userId);
serialExecute(collectionCases, runModeConfig, null, project, userId);
}
}
} else {
@ -141,8 +148,12 @@ public class TestPlanApiScenarioBatchRunService {
// 生成测试集队列
ExecutionQueue collectionQueue = apiBatchRunBaseService.initExecutionqueue(serialCollectionIds,
ApiExecuteResourceType.TEST_PLAN_API_SCENARIO.name(), userId);
Map<String, List<String>> collectionIdMap = collectionMap.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().stream().map(TestPlanApiScenarioBatchRunDTO::getId).toList()));
// 记录各测试集中要执行的用例
apiExecutionMapService.initMap(collectionQueue.getQueueId(), collectionMap);
apiExecutionMapService.initMap(collectionQueue.getQueueId(), collectionIdMap);
executeNextCollection(collectionQueue.getQueueId());
}
@ -160,12 +171,12 @@ public class TestPlanApiScenarioBatchRunService {
return testPlanCollections;
}
private Map<String, List<String>> getCollectionMap(List<TestPlanApiScenario> testPlanApiScenarios) {
Map<String, List<String>> collectionMap = new HashMap<>();
for (TestPlanApiScenario testPlanApiScenario : testPlanApiScenarios) {
private Map<String, List<TestPlanApiScenarioBatchRunDTO>> getCollectionMap(List<TestPlanApiScenarioBatchRunDTO> testPlanApiScenarios) {
Map<String, List<TestPlanApiScenarioBatchRunDTO>> collectionMap = new HashMap<>();
for (TestPlanApiScenarioBatchRunDTO testPlanApiScenario : testPlanApiScenarios) {
collectionMap.putIfAbsent(testPlanApiScenario.getTestPlanCollectionId(), new ArrayList<>());
List<String> ids = collectionMap.get(testPlanApiScenario.getTestPlanCollectionId());
ids.add(testPlanApiScenario.getId());
collectionMap.get(testPlanApiScenario.getTestPlanCollectionId())
.add(testPlanApiScenario);
}
return collectionMap;
}
@ -180,14 +191,17 @@ public class TestPlanApiScenarioBatchRunService {
ExecutionQueueDetail nextDetail = apiExecutionQueueService.getNextDetail(collectionQueueId);
String collectionId = nextDetail.getResourceId();
List<String> ids = apiExecutionMapService.getAndRemove(collectionQueueId, collectionId);
List<TestPlanApiScenarioBatchRunDTO> testPlanApiScenarios = getBatchRunInfo(ids);
TestPlanCollection collection = testPlanCollectionMapper.selectByPrimaryKey(collectionId);
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(collection.getTestPlanId());
Project project = projectMapper.selectByPrimaryKey(testPlan.getProjectId());
ApiRunModeConfigDTO runModeConfig = testPlanApiBatchRunBaseService.getApiRunModeConfig(collection);
if (apiBatchRunBaseService.isParallel(runModeConfig.getRunMode())) {
String testPlanId = collection.getTestPlanId();
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(testPlanId);
parallelExecute(ids, runModeConfig, testPlan.getProjectId(), collectionQueueId, userId);
parallelExecute(testPlanApiScenarios, runModeConfig, collectionQueueId, project, userId);
} else {
serialExecute(ids, runModeConfig, collectionQueueId, userId);
serialExecute(testPlanApiScenarios, runModeConfig, collectionQueueId, project, userId);
}
}
@ -199,9 +213,15 @@ public class TestPlanApiScenarioBatchRunService {
* 串行批量执行
*
*/
public void serialExecute(List<String> ids, ApiRunModeConfigDTO runModeConfig, String parentQueueId, String userId) {
public void serialExecute(List<TestPlanApiScenarioBatchRunDTO> testPlanApiScenarios, ApiRunModeConfigDTO runModeConfig, String parentQueueId, Project project, String userId) {
// 初始化任务
ExecTask execTask = initExecTask(testPlanApiScenarios.size(), runModeConfig, project, userId);
// 初始化任务项
List<ExecTaskItem> execTaskItems = initExecTaskItem(testPlanApiScenarios, userId, project, execTask);
// 先初始化集成报告设置好报告ID再初始化执行队列
ExecutionQueue queue = apiBatchRunBaseService.initExecutionqueue(ids, runModeConfig, ApiExecuteResourceType.TEST_PLAN_API_SCENARIO.name(), parentQueueId, userId);
ExecutionQueue queue = apiBatchRunBaseService.initExecutionQueue(execTask.getId(), runModeConfig, ApiExecuteResourceType.TEST_PLAN_API_SCENARIO.name(), parentQueueId, userId);
// 初始化队列项
apiBatchRunBaseService.initExecutionQueueDetails(queue.getQueueId(), execTaskItems);
// 执行第一个任务
ExecutionQueueDetail nextDetail = apiExecutionQueueService.getNextDetail(queue.getQueueId());
executeNextTask(queue, nextDetail);
@ -211,65 +231,76 @@ public class TestPlanApiScenarioBatchRunService {
* 并行批量执行
*
*/
public void parallelExecute(List<String> ids, ApiRunModeConfigDTO runModeConfig, String projectId, String parentQueueId, String userId) {
public void parallelExecute(List<TestPlanApiScenarioBatchRunDTO> testPlanApiScenarios, ApiRunModeConfigDTO runModeConfig, String parentQueueId, Project project, String userId) {
Map<String, String> scenarioReportMap = initReport(ids, runModeConfig, userId);
Map<String, String> scenarioReportMap = initReport(testPlanApiScenarios, runModeConfig, project.getId(), userId);
List<TaskItem> taskItems = ids.stream()
.map(id -> apiExecuteService.getTaskItem(scenarioReportMap.get(id), id)).toList();
// 初始化任务
ExecTask execTask = initExecTask(testPlanApiScenarios.size(), runModeConfig, project, userId);
TaskBatchRequestDTO taskRequest = getTaskBatchRequestDTO(projectId, runModeConfig);
// 初始化任务项
Map<String, String> resourceExecTaskItemMap = initExecTaskItem(testPlanApiScenarios, userId, project, execTask)
.stream()
.collect(Collectors.toMap(ExecTaskItem::getResourceId, ExecTaskItem::getId));
List<TaskItem> taskItems = testPlanApiScenarios.stream()
.map(testPlanApiScenario -> {
String id = testPlanApiScenario.getId();
TaskItem taskItem = apiExecuteService.getTaskItem(scenarioReportMap.get(id), id);
taskItem.setId(resourceExecTaskItemMap.get(id));
return taskItem;
}).toList();
TaskBatchRequestDTO taskRequest = getTaskBatchRequestDTO(project.getId(), runModeConfig);
taskRequest.setTaskItems(taskItems);
taskRequest.getTaskInfo().setTaskId(execTask.getId());
taskRequest.getTaskInfo().setUserId(userId);
taskRequest.getTaskInfo().setParentQueueId(parentQueueId);
apiExecuteService.batchExecute(taskRequest);
}
private Map<String, String> initReport(List<String> ids, ApiRunModeConfigDTO runModeConfig, String userId) {
List<TestPlanApiScenario> testPlanApiScenarios = new ArrayList<>(ids.size());
List<ApiScenario> apiScenarios = new ArrayList<>(ids.size());
// 分批查询
List<TestPlanApiScenario> finalTestPlanApiScenarios = testPlanApiScenarios;
SubListUtils.dealForSubList(ids, 100, subIds -> finalTestPlanApiScenarios.addAll(extTestPlanApiScenarioMapper.getScenarioExecuteInfoByIds(subIds)));
List<String> caseIds = testPlanApiScenarios.stream().map(TestPlanApiScenario::getApiScenarioId).toList();
List<ApiScenario> finalApiScenarios = apiScenarios;
SubListUtils.dealForSubList(caseIds, 100, subIds -> finalApiScenarios.addAll(extApiScenarioMapper.getScenarioExecuteInfoByIds(subIds)));
Map<String, ApiScenario> apiScenarioMap = apiScenarios.stream()
.collect(Collectors.toMap(ApiScenario::getId, Function.identity()));
Map<String, TestPlanApiScenario> testPlanApiScenarioMap = testPlanApiScenarios.stream()
.collect(Collectors.toMap(TestPlanApiScenario::getId, Function.identity()));
testPlanApiScenarios = new ArrayList<>(ids.size());
for (String id : ids) {
// 按照ID顺序排序
TestPlanApiScenario testPlanApiScenario = testPlanApiScenarioMap.get(id);
if (testPlanApiScenario == null) {
break;
}
testPlanApiScenarios.add(testPlanApiScenario);
private ExecTask initExecTask(int caseSize, ApiRunModeConfigDTO runModeConfig, Project project, String userId) {
ExecTask execTask = apiCommonService.newExecTask(project.getId(), userId);
execTask.setCaseCount(Long.valueOf(caseSize));
if (runModeConfig.isIntegratedReport()) {
execTask.setTaskName(runModeConfig.getCollectionReport().getReportName());
} else {
execTask.setTaskName(Translator.get("api_batch_task_name"));
}
// 初始化独立报告执行时初始化步骤
return initScenarioReport(runModeConfig, testPlanApiScenarios, apiScenarioMap, userId);
execTask.setOrganizationId(project.getOrganizationId());
execTask.setTriggerMode(TaskTriggerMode.MANUAL.name());
execTask.setTaskType(ExecTaskType.TEST_PLAN_API_SCENARIO.name());
baseTaskHubService.insertExecTask(execTask);
return execTask;
}
public Map<String, String> initScenarioReport(ApiRunModeConfigDTO runModeConfig, List<TestPlanApiScenario> testPlanApiScenarios,
Map<String, ApiScenario> apiScenarioMap, String userId) {
private List<ExecTaskItem> initExecTaskItem(List<TestPlanApiScenarioBatchRunDTO> apiTestCases, String userId, Project project, ExecTask execTask) {
List<ExecTaskItem> execTaskItems = new ArrayList<>(apiTestCases.size());
for (TestPlanApiScenarioBatchRunDTO testPlanApiScenario : apiTestCases) {
ExecTaskItem execTaskItem = apiCommonService.newExecTaskItem(execTask.getId(), project.getId(), userId);
execTaskItem.setOrganizationId(project.getOrganizationId());
execTaskItem.setResourceType(ApiExecuteResourceType.TEST_PLAN_API_SCENARIO.name());
execTaskItem.setResourceId(testPlanApiScenario.getId());
execTaskItem.setResourceName(testPlanApiScenario.getName());
execTaskItems.add(execTaskItem);
}
baseTaskHubService.insertExecTaskDetail(execTaskItems);
return execTaskItems;
}
public Map<String, String> initReport( List<TestPlanApiScenarioBatchRunDTO> testPlanApiScenarios,
ApiRunModeConfigDTO runModeConfig, String projectId, String userId) {
List<ApiScenarioReport> apiScenarioReports = new ArrayList<>(testPlanApiScenarios.size());
List<ApiScenarioRecord> apiScenarioRecords = new ArrayList<>(testPlanApiScenarios.size());
Map<String, String> resourceReportMap = new HashMap<>();
for (TestPlanApiScenario testPlanApiScenario : testPlanApiScenarios) {
ApiScenario apiScenario = apiScenarioMap.get(testPlanApiScenario.getApiScenarioId());
for (TestPlanApiScenarioBatchRunDTO testPlanApiScenario : testPlanApiScenarios) {
// 初始化报告
ApiScenarioReport apiScenarioReport = getScenarioReport(runModeConfig, testPlanApiScenario, apiScenario, userId);
ApiScenarioReport apiScenarioReport = getScenarioReport(runModeConfig, testPlanApiScenario, projectId, userId);
apiScenarioReport.setId(IDGenerator.nextStr());
apiScenarioReports.add(apiScenarioReport);
// 创建报告和用例的关联关系
ApiScenarioRecord apiScenarioRecord = apiScenarioRunService.getApiScenarioRecord(apiScenario, apiScenarioReport);
ApiScenarioRecord apiScenarioRecord = apiScenarioRunService.getApiScenarioRecord(testPlanApiScenario.getApiScenarioId(), apiScenarioReport);
apiScenarioRecords.add(apiScenarioRecord);
resourceReportMap.put(testPlanApiScenario.getId(), apiScenarioReport.getId());
}
@ -287,14 +318,19 @@ public class TestPlanApiScenarioBatchRunService {
ApiRunModeConfigDTO runModeConfig = queue.getRunModeConfig();
TestPlanApiScenario testPlanApiScenario = testPlanApiScenarioMapper.selectByPrimaryKey(queueDetail.getResourceId());
ApiScenario apiScenario = apiScenarioMapper.selectByPrimaryKey(testPlanApiScenario.getApiScenarioId());
String testPlanId = testPlanApiScenario.getTestPlanId();
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(testPlanId);
// 独立报告执行到当前任务时初始化报告
String reportId = initScenarioReport(runModeConfig, testPlanApiScenario, apiScenario, queue.getUserId()).getApiScenarioReportId();
String reportId = initScenarioReport(runModeConfig, BeanUtils.copyBean(new TestPlanApiScenarioBatchRunDTO(), testPlanApiScenario), testPlan.getId(), queue.getUserId())
.getApiScenarioReportId();
TaskRequestDTO taskRequest = getTaskRequestDTO(apiScenario.getProjectId(), queue.getRunModeConfig());
TaskItem taskItem = apiExecuteService.getTaskItem(reportId, queueDetail.getResourceId());
taskItem.setId(queueDetail.getTaskItemId());
taskRequest.setTaskItem(taskItem);
taskRequest.getTaskInfo().setQueueId(queue.getQueueId());
taskRequest.getTaskInfo().setTaskId(queue.getTaskId());
taskRequest.getTaskInfo().setUserId(queue.getUserId());
taskRequest.getTaskInfo().setParentQueueId(queue.getParentQueueId());
@ -308,6 +344,44 @@ public class TestPlanApiScenarioBatchRunService {
return taskRequest;
}
public List<TestPlanApiScenarioBatchRunDTO> getSelectIdAndCollectionId(TestPlanApiScenarioBatchRunRequest request) {
if (request.isSelectAll()) {
List<TestPlanApiScenarioBatchRunDTO> testPlanApiCases = extTestPlanApiScenarioMapper.getSelectIdAndCollectionId(request);
if (CollectionUtils.isNotEmpty(request.getExcludeIds())) {
testPlanApiCases.removeAll(request.getExcludeIds());
}
return testPlanApiCases;
} else {
return getBatchRunInfo(request.getSelectIds());
}
}
private List<TestPlanApiScenarioBatchRunDTO> getBatchRunInfo(List<String> ids) {
List<TestPlanApiScenarioBatchRunDTO> testPlanApiScenarios = new ArrayList<>();
SubListUtils.dealForSubList(ids, 200, (subIds) -> testPlanApiScenarios.addAll(extTestPlanApiScenarioMapper.getBatchRunInfoByIds(subIds)));
// 查询用例名称信息
List<String> caseIds = testPlanApiScenarios.stream().map(TestPlanApiScenarioBatchRunDTO::getApiScenarioId).collect(Collectors.toList());
Map<String, String> apiScenarioNameMap = extApiScenarioMapper.getNameInfo(caseIds)
.stream()
.collect(Collectors.toMap(ApiScenario::getId, ApiScenario::getName));
Map<String, TestPlanApiScenarioBatchRunDTO> testPlanApiCaseMap = testPlanApiScenarios
.stream()
.collect(Collectors.toMap(TestPlanApiScenarioBatchRunDTO::getId, Function.identity()));
testPlanApiScenarios.clear();
// 按ID的顺序排序
for (String id : ids) {
TestPlanApiScenarioBatchRunDTO testPlanApiCase = testPlanApiCaseMap.get(id);
if (testPlanApiCase != null) {
testPlanApiCase.setName(apiScenarioNameMap.get(testPlanApiCase.getApiScenarioId()));
testPlanApiScenarios.add(testPlanApiCase);
}
}
return testPlanApiScenarios;
}
public TaskBatchRequestDTO getTaskBatchRequestDTO(String projectId, ApiRunModeConfigDTO runModeConfig) {
TaskBatchRequestDTO taskRequest = new TaskBatchRequestDTO();
TaskInfo taskInfo = getTaskInfo(projectId, runModeConfig);
@ -325,35 +399,29 @@ public class TestPlanApiScenarioBatchRunService {
* 预生成用例的执行报告
*
* @param runModeConfig
* @param apiScenario
* @param testPlanApiScenario
* @return
*/
public ApiScenarioRecord initScenarioReport(ApiRunModeConfigDTO runModeConfig, TestPlanApiScenario testPlanApiScenario,
ApiScenario apiScenario, String userId) {
public ApiScenarioRecord initScenarioReport(ApiRunModeConfigDTO runModeConfig, TestPlanApiScenarioBatchRunDTO testPlanApiScenario, String projectId, String userId) {
// 初始化报告
ApiScenarioReport apiScenarioReport = getScenarioReport(runModeConfig, testPlanApiScenario, apiScenario, userId);
ApiScenarioReport apiScenarioReport = getScenarioReport(runModeConfig, testPlanApiScenario, projectId, userId);
apiScenarioReport.setId(IDGenerator.nextStr());
// 创建报告和用例的关联关系
ApiScenarioRecord apiScenarioRecord = apiScenarioRunService.getApiScenarioRecord(apiScenario, apiScenarioReport);
ApiScenarioRecord apiScenarioRecord = apiScenarioRunService.getApiScenarioRecord(testPlanApiScenario.getApiScenarioId(), apiScenarioReport);
apiScenarioReportService.insertApiScenarioReport(List.of(apiScenarioReport), List.of(apiScenarioRecord));
return apiScenarioRecord;
}
private ApiScenarioReport getScenarioReport(ApiRunModeConfigDTO runModeConfig, TestPlanApiScenario testPlanApiScenario, ApiScenario apiScenario, String userId) {
ApiScenarioReport apiScenarioReport = getScenarioReport(runModeConfig, apiScenario, userId);
apiScenarioReport.setTestPlanScenarioId(testPlanApiScenario.getId());
apiScenarioReport.setEnvironmentId(apiBatchRunBaseService.getEnvId(runModeConfig, testPlanApiScenario.getEnvironmentId()));
return apiScenarioReport;
}
public ApiScenarioReport getScenarioReport(ApiRunModeConfigDTO runModeConfig, ApiScenario apiScenario, String userId) {
private ApiScenarioReport getScenarioReport(ApiRunModeConfigDTO runModeConfig, TestPlanApiScenarioBatchRunDTO testPlanApiScenario, String projectId, String userId) {
ApiScenarioReport apiScenarioReport = apiScenarioRunService.getScenarioReport(userId);
apiScenarioReport.setName(apiScenario.getName() + "_" + DateUtils.getTimeString(System.currentTimeMillis()));
apiScenarioReport.setProjectId(apiScenario.getProjectId());
apiScenarioReport.setName(testPlanApiScenario.getName() + "_" + DateUtils.getTimeString(System.currentTimeMillis()));
apiScenarioReport.setProjectId(projectId);
apiScenarioReport.setEnvironmentId(runModeConfig.getEnvironmentId());
apiScenarioReport.setRunMode(runModeConfig.getRunMode());
apiScenarioReport.setPoolId(runModeConfig.getPoolId());
apiScenarioReport.setTriggerMode(TaskTriggerMode.BATCH.name());
apiScenarioReport.setTestPlanScenarioId(testPlanApiScenario.getId());
apiScenarioReport.setEnvironmentId(apiBatchRunBaseService.getEnvId(runModeConfig, testPlanApiScenario.getEnvironmentId()));
return apiScenarioReport;
}
}

View File

@ -8,6 +8,7 @@ import io.metersphere.api.mapper.ApiScenarioModuleMapper;
import io.metersphere.api.mapper.ApiScenarioReportMapper;
import io.metersphere.api.mapper.ExtApiScenarioMapper;
import io.metersphere.api.service.ApiBatchRunBaseService;
import io.metersphere.api.service.ApiCommonService;
import io.metersphere.api.service.ApiExecuteService;
import io.metersphere.api.service.scenario.ApiScenarioModuleService;
import io.metersphere.api.service.scenario.ApiScenarioReportService;
@ -43,6 +44,8 @@ import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.CommonBeanFactory;
import io.metersphere.sdk.util.SubListUtils;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.domain.ExecTask;
import io.metersphere.system.domain.ExecTaskItem;
import io.metersphere.system.dto.LogInsertModule;
import io.metersphere.system.dto.ModuleSelectDTO;
import io.metersphere.system.dto.sdk.BaseTreeNode;
@ -113,6 +116,8 @@ public class TestPlanApiScenarioService extends TestPlanResourceService {
private ExtApiScenarioMapper extApiScenarioMapper;
@Resource
private TestPlanConfigService testPlanConfigService;
@Resource
private ApiCommonService apiCommonService;
private static final String EXECUTOR = "executeUserName";
@ -331,13 +336,33 @@ public class TestPlanApiScenarioService extends TestPlanResourceService {
ApiRunModeConfigDTO runModeConfig = testPlanApiBatchRunBaseService.getApiRunModeConfig(testPlanApiScenario.getTestPlanCollectionId());
runModeConfig.setEnvironmentId(apiBatchRunBaseService.getEnvId(runModeConfig, testPlanApiScenario.getEnvironmentId()));
TaskRequestDTO taskRequest = getTaskRequest(reportId, id, apiScenario.getProjectId(), ApiExecuteRunMode.RUN.name());
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(testPlanApiScenario.getTestPlanId());
Project project = projectMapper.selectByPrimaryKey(testPlan.getProjectId());
ExecTask execTask = apiCommonService.newExecTask(project.getId(), userId);
execTask.setCaseCount(1L);
execTask.setTaskName(apiScenario.getName());
execTask.setOrganizationId(project.getOrganizationId());
execTask.setTriggerMode(TaskTriggerMode.MANUAL.name());
execTask.setTaskType(ExecTaskType.TEST_PLAN_API_SCENARIO.name());
ExecTaskItem execTaskItem = apiCommonService.newExecTaskItem(execTask.getId(), project.getId(), userId);
execTaskItem.setOrganizationId(project.getOrganizationId());
execTaskItem.setResourceType(ApiExecuteResourceType.TEST_PLAN_API_SCENARIO.name());
execTaskItem.setResourceId(testPlanApiScenario.getId());
execTaskItem.setResourceName(apiScenario.getName());
TaskInfo taskInfo = taskRequest.getTaskInfo();
TaskItem taskItem = taskRequest.getTaskItem();
taskInfo.setTaskId(execTask.getId());
taskInfo.setRunModeConfig(runModeConfig);
taskInfo.setSaveResult(true);
taskInfo.setRealTime(true);
taskInfo.setUserId(userId);
TaskItem taskItem = taskRequest.getTaskItem();
taskItem.setId(execTaskItem.getId());
if (StringUtils.isEmpty(taskItem.getReportId())) {
taskInfo.setRealTime(false);
reportId = IDGenerator.nextStr();
@ -748,31 +773,6 @@ public class TestPlanApiScenarioService extends TestPlanResourceService {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
public List<TestPlanApiScenario> getSelectIdAndCollectionId(TestPlanApiScenarioBatchRunRequest request) {
if (request.isSelectAll()) {
List<TestPlanApiScenario> testPlanApiCases = extTestPlanApiScenarioMapper.getSelectIdAndCollectionId(request);
if (CollectionUtils.isNotEmpty(request.getExcludeIds())) {
testPlanApiCases.removeAll(request.getExcludeIds());
}
return testPlanApiCases;
} else {
TestPlanApiScenarioExample example = new TestPlanApiScenarioExample();
example.createCriteria().andIdIn(request.getSelectIds());
Map<String, TestPlanApiScenario> testPlanApiScenarioMap = testPlanApiScenarioMapper.selectByExample(example)
.stream()
.collect(Collectors.toMap(TestPlanApiScenario::getId, Function.identity()));
List<TestPlanApiScenario> testPlanApiScenarios = new ArrayList<>(request.getSelectIds().size());
// 按ID的顺序排序
for (String id : request.getSelectIds()) {
TestPlanApiScenario testPlanApiScenario = testPlanApiScenarioMap.get(id);
if (testPlanApiScenario != null) {
testPlanApiScenarios.add(testPlanApiScenario);
}
}
return testPlanApiScenarios;
}
}
/**
* 处理执行人为空过滤参数
*

View File

@ -1,16 +1,21 @@
package io.metersphere.plan.service;
import com.esotericsoftware.minlog.Log;
import io.metersphere.api.service.ApiCommonService;
import io.metersphere.plan.domain.*;
import io.metersphere.plan.dto.request.TestPlanBatchExecuteRequest;
import io.metersphere.plan.dto.request.TestPlanExecuteRequest;
import io.metersphere.plan.dto.request.TestPlanReportGenRequest;
import io.metersphere.plan.mapper.*;
import io.metersphere.project.domain.Project;
import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.sdk.constants.*;
import io.metersphere.sdk.dto.queue.TestPlanExecutionQueue;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.LogUtils;
import io.metersphere.system.domain.ExecTask;
import io.metersphere.system.service.BaseTaskHubService;
import io.metersphere.system.uid.IDGenerator;
import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
@ -52,6 +57,16 @@ public class TestPlanExecuteService {
private TestPlanReportMapper testPlanReportMapper;
@Resource
private TestPlanExecuteSupportService testPlanExecuteSupportService;
@Resource
private ApiCommonService apiCommonService;
@Resource
private BaseTaskHubService baseTaskHubService;
@Resource
private ProjectMapper projectMapper;
@Resource
private ExtTestPlanApiCaseMapper extTestPlanApiCaseMapper;
@Resource
private ExtTestPlanApiScenarioMapper extTestPlanApiScenarioMapper;
// 停止测试计划的执行
public void stopTestPlanRunning(String testPlanReportId) {
@ -139,7 +154,8 @@ public class TestPlanExecuteService {
request.getExecuteId(),
request.getRunMode(),
request.getExecutionSource(),
reportId
reportId,
IDGenerator.nextStr()
);
testPlanExecuteSupportService.setRedisForList(
@ -180,6 +196,7 @@ public class TestPlanExecuteService {
testPlanId,
runMode,
TaskTriggerMode.BATCH.name(),
IDGenerator.nextStr(),
IDGenerator.nextStr()
)
);
@ -208,6 +225,12 @@ public class TestPlanExecuteService {
throw new MSException("test_plan.error");
}
Project project = projectMapper.selectByPrimaryKey(testPlan.getProjectId());
Integer caseTotal = extTestPlanApiCaseMapper.countByPlanId(testPlan.getId()) + extTestPlanApiScenarioMapper.countByPlanId(testPlan.getId());
// 初始化任务
ExecTask execTask = initExecTask(executionQueue.getTaskId(), caseTotal, testPlan.getName(), project, executionQueue.getCreateUser(), executionQueue.getExecutionSource());
TestPlanReportGenRequest genReportRequest = new TestPlanReportGenRequest();
genReportRequest.setTriggerMode(executionQueue.getExecutionSource());
genReportRequest.setTestPlanId(executionQueue.getSourceID());
@ -216,7 +239,7 @@ public class TestPlanExecuteService {
List<TestPlan> children = testPlanService.selectNotArchivedChildren(testPlan.getId());
// 预生成计划组报告
Map<String, String> reportMap = testPlanReportService.genReportByExecution(executionQueue.getPrepareReportId(), genReportRequest, executionQueue.getCreateUser());
Map<String, String> reportMap = testPlanReportService.genReportByExecution(executionQueue.getPrepareReportId(), execTask.getId(), genReportRequest, executionQueue.getCreateUser());
long pos = 0;
List<TestPlanExecutionQueue> childrenQueue = new ArrayList<>();
@ -235,7 +258,8 @@ public class TestPlanExecuteService {
child.getId(),
executionQueue.getRunMode(),
executionQueue.getExecutionSource(),
reportMap.get(child.getId())
reportMap.get(child.getId()),
executionQueue.getTaskId()
)
);
}
@ -265,7 +289,7 @@ public class TestPlanExecuteService {
return executionQueue.getPrepareReportId();
} else {
Map<String, String> reportMap = testPlanReportService.genReportByExecution(executionQueue.getPrepareReportId(), genReportRequest, executionQueue.getCreateUser());
Map<String, String> reportMap = testPlanReportService.genReportByExecution(executionQueue.getPrepareReportId(), execTask.getId(), genReportRequest, executionQueue.getCreateUser());
executionQueue.setPrepareReportId(reportMap.get(executionQueue.getSourceID()));
testPlanService.setExecuteConfig(executionQueue.getSourceID(), executionQueue.getPrepareReportId());
this.executeTestPlan(executionQueue);
@ -273,6 +297,18 @@ public class TestPlanExecuteService {
}
}
private ExecTask initExecTask(String taskId, int caseSize, String name, Project project, String userId, String triggerMode) {
ExecTask execTask = apiCommonService.newExecTask(project.getId(), userId);
execTask.setId(taskId);
execTask.setCaseCount(Long.valueOf(caseSize));
execTask.setTaskName(name);
execTask.setOrganizationId(project.getOrganizationId());
execTask.setTriggerMode(TaskTriggerMode.MANUAL.name());
execTask.setTaskType(ExecTaskType.TEST_PLAN.name());
baseTaskHubService.insertExecTask(execTask);
return execTask;
}
//执行测试计划里不同类型的用例 回调caseTypeExecuteQueueFinish
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void executeTestPlan(TestPlanExecutionQueue executionQueue) {
@ -310,7 +346,8 @@ public class TestPlanExecuteService {
collection.getId(),
runMode,
executionQueue.getExecutionSource(),
executionQueue.getPrepareReportId())
executionQueue.getPrepareReportId(),
executionQueue.getTaskId())
);
}
LogUtils.info("测试计划执行节点 --- 队列ID[{}],队列类型[{}],父队列ID[{}],父队列类型[{}],执行模式[{}]", queueId, queueType, executionQueue.getParentQueueId(), executionQueue.getParentQueueType(), runMode);
@ -362,7 +399,8 @@ public class TestPlanExecuteService {
collection.getId(),
runMode,
executionQueue.getExecutionSource(),
executionQueue.getPrepareReportId()) {{
executionQueue.getPrepareReportId(),
executionQueue.getTaskId()) {{
this.setTestPlanCollectionJson(JSON.toJSONString(collection));
}}
);

View File

@ -1,6 +1,7 @@
package io.metersphere.plan.service;
import com.google.common.collect.Maps;
import io.metersphere.api.service.ApiCommonService;
import io.metersphere.bug.dto.response.BugDTO;
import io.metersphere.bug.service.BugCommonService;
import io.metersphere.plan.constants.AssociateCaseType;
@ -16,6 +17,8 @@ import io.metersphere.plan.enums.TestPlanReportAttachmentSourceType;
import io.metersphere.plan.mapper.*;
import io.metersphere.plan.utils.CountUtils;
import io.metersphere.plugin.platform.dto.SelectOption;
import io.metersphere.project.domain.Project;
import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.sdk.constants.*;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.file.FileCenter;
@ -23,11 +26,13 @@ import io.metersphere.sdk.file.FileCopyRequest;
import io.metersphere.sdk.file.FileRepository;
import io.metersphere.sdk.file.FileRequest;
import io.metersphere.sdk.util.*;
import io.metersphere.system.domain.ExecTaskItem;
import io.metersphere.system.domain.User;
import io.metersphere.system.dto.sdk.OptionDTO;
import io.metersphere.system.mapper.BaseUserMapper;
import io.metersphere.system.mapper.UserMapper;
import io.metersphere.system.notice.constants.NoticeConstants;
import io.metersphere.system.service.BaseTaskHubService;
import io.metersphere.system.service.CommonFileService;
import io.metersphere.system.service.FileService;
import io.metersphere.system.service.SimpleUserService;
@ -110,6 +115,12 @@ public class TestPlanReportService {
private TestPlanReportComponentMapper componentMapper;
@Resource
private CommonFileService commonFileService;
@Resource
private ApiCommonService apiCommonService;
@Resource
private BaseTaskHubService baseTaskHubService;
@Resource
private ProjectMapper projectMapper;
private static final int MAX_REPORT_NAME_LENGTH = 300;
@ -308,8 +319,13 @@ public class TestPlanReportService {
* @param currentUser 当前用户
*/
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public Map<String, String> genReportByExecution(String prepareReportId, TestPlanReportGenRequest request, String currentUser) {
return genReport(prepareReportId, request, false, currentUser, null);
public Map<String, String> genReportByExecution(String prepareReportId, String taskId, TestPlanReportGenRequest request, String currentUser) {
return genReport(prepareReportId, taskId, request, false, currentUser, null);
}
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public Map<String, String> genReport(String prepareReportId, TestPlanReportGenRequest request, boolean manual, String currentUser, String manualReportName) {
return genReport(prepareReportId, null, request, manual, currentUser, manualReportName);
}
/**
@ -321,7 +337,7 @@ public class TestPlanReportService {
* @param currentUser 当前用户
* @param manualReportName 手动生成报告名称
*/
public Map<String, String> genReport(String prepareReportId, TestPlanReportGenRequest request, boolean manual, String currentUser, String manualReportName) {
public Map<String, String> genReport(String prepareReportId, String taskId, TestPlanReportGenRequest request, boolean manual, String currentUser, String manualReportName) {
Map<String, String> preReportMap = Maps.newHashMapWithExpectedSize(8);
TestPlanReportManualParam reportManualParam = TestPlanReportManualParam.builder().manualName(manualReportName).targetId(request.getTestPlanId()).build();
try {
@ -345,6 +361,7 @@ public class TestPlanReportService {
genPreParam.setStartTime(null);
}
genPreParam.setUseManual(manual);
genPreParam.setTaskId(taskId);
// 如果是测试计划的独立报告使用参数中的预生成的报告id否则只有测试计划组报告使用该id
String prepareItemReportId = isGroupReports ? IDGenerator.nextStr() : prepareReportId;
TestPlanReport preReport = preGenReport(prepareItemReportId, genPreParam, currentUser, childPlanIds, reportManualParam);
@ -437,6 +454,8 @@ public class TestPlanReportService {
List<ReportBugCountDTO> bugCountList = extTestPlanReportBugMapper.countPlanBug(genParam.getTestPlanId());
Map<String, Long> bugCountMap = bugCountList.stream().collect(Collectors.toMap(ReportBugCountDTO::getRefCaseId, ReportBugCountDTO::getBugCount));
Project project = projectMapper.selectByPrimaryKey(genParam.getProjectId());
AtomicLong funcCaseCount = new AtomicLong();
AtomicLong apiCaseCount = new AtomicLong();
AtomicLong apiScenarioCount = new AtomicLong();
@ -525,6 +544,11 @@ public class TestPlanReportService {
TestPlanReportApiCaseMapper batchMapper = sqlSession.getMapper(TestPlanReportApiCaseMapper.class);
batchMapper.batchInsert(reportApiCases);
sqlSession.flushStatements();
if (StringUtils.isNotBlank(genParam.getTaskId())) {
reportApiCases.sort(Comparator.comparing(TestPlanReportApiCase::getPos).reversed());
initApiCaseExecTaskItem(genParam.getTaskId(), reportApiCases, report.getCreateUser(), project);
}
});
}
testPlanReportApiCaseIdList = null;
@ -563,6 +587,11 @@ public class TestPlanReportService {
TestPlanReportApiScenarioMapper batchMapper = sqlSession.getMapper(TestPlanReportApiScenarioMapper.class);
batchMapper.batchInsert(reportApiScenarios);
sqlSession.flushStatements();
if (StringUtils.isNotBlank(genParam.getTaskId())) {
reportApiScenarios.sort(Comparator.comparing(TestPlanReportApiScenario::getPos).reversed());
initScenarioExecTaskItem(genParam.getTaskId(), reportApiScenarios, report.getCreateUser(), project);
}
});
}
reportApiScenarioIdList = null;
@ -611,6 +640,31 @@ public class TestPlanReportService {
.functionCaseCount(funcCaseCount.get()).apiCaseCount(apiCaseCount.get()).apiScenarioCount(apiScenarioCount.get()).bugCount(bugCount.get()).build();
}
private void initApiCaseExecTaskItem(String taskId, List<TestPlanReportApiCase> apiTestCases, String userId, Project project) {
List<ExecTaskItem> execTaskItems = new ArrayList<>(apiTestCases.size());
for (TestPlanReportApiCase apiTestCase : apiTestCases) {
ExecTaskItem execTaskItem = apiCommonService.newExecTaskItem(taskId, project.getId(), userId);
execTaskItem.setOrganizationId(project.getOrganizationId());
execTaskItem.setResourceType(ApiExecuteResourceType.PLAN_RUN_API_CASE.name());
execTaskItem.setResourceId(apiTestCase.getId());
execTaskItem.setResourceName(apiTestCase.getApiCaseName());
execTaskItems.add(execTaskItem);
}
baseTaskHubService.insertExecTaskDetail(execTaskItems);
}
private void initScenarioExecTaskItem(String taskId, List<TestPlanReportApiScenario> testPlanReportApiScenarios, String userId, Project project) {
List<ExecTaskItem> execTaskItems = new ArrayList<>(testPlanReportApiScenarios.size());
for (TestPlanReportApiScenario testPlanReportApiScenario : testPlanReportApiScenarios) {
ExecTaskItem execTaskItem = apiCommonService.newExecTaskItem(taskId, project.getId(), userId);
execTaskItem.setOrganizationId(project.getOrganizationId());
execTaskItem.setResourceType(ApiExecuteResourceType.PLAN_RUN_API_SCENARIO.name());
execTaskItem.setResourceId(testPlanReportApiScenario.getId());
execTaskItem.setResourceName(testPlanReportApiScenario.getApiScenarioName());
execTaskItems.add(execTaskItem);
}
baseTaskHubService.insertExecTaskDetail(execTaskItems);
}
/**
* 报告结果后置处理 (汇总操作结束后调用)