refactor(接口测试): 重构接口执行
This commit is contained in:
parent
18c713238d
commit
8a307bb87d
|
@ -0,0 +1,41 @@
|
|||
package io.metersphere.sdk.dto.api.task;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 获取执行脚本请求参数
|
||||
*/
|
||||
@Data
|
||||
public class GetRunScriptRequest implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* 任务项
|
||||
*/
|
||||
private TaskItem taskItem;
|
||||
/**
|
||||
* 操作人
|
||||
*/
|
||||
private String userId;
|
||||
/**
|
||||
* {@link io.metersphere.sdk.constants.ApiExecuteRunMode}
|
||||
*/
|
||||
@NotBlank
|
||||
private String runMode;
|
||||
/**
|
||||
* 运行配置
|
||||
*/
|
||||
@Valid
|
||||
private ApiRunModeConfigDTO runModeConfig = new ApiRunModeConfigDTO();
|
||||
/**
|
||||
* 资源类型
|
||||
*
|
||||
* @see io.metersphere.sdk.constants.ApiExecuteResourceType
|
||||
*/
|
||||
private String resourceType;
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package io.metersphere.sdk.dto.api.task;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 获取执行脚本请求结果
|
||||
*/
|
||||
@Data
|
||||
public class GetRunScriptResult implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 执行脚本
|
||||
*/
|
||||
private String script;
|
||||
|
||||
/**
|
||||
* 要执行的请求总量,用于计算执行各种指标
|
||||
*/
|
||||
private Long requestCount;
|
||||
/**
|
||||
* 执行所需的文件
|
||||
*/
|
||||
private TaskResourceFile taskResourceFile;
|
||||
/**
|
||||
* 场景执行时关联的其他项目的步骤所需的资源
|
||||
*/
|
||||
private TaskProjectResource refProjectResource = new TaskProjectResource();
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package io.metersphere.sdk.dto.api.task;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 任务请求参数数据
|
||||
*/
|
||||
@Data
|
||||
public class TaskBatchRequestDTO implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 任务的基本信息
|
||||
*/
|
||||
@Valid
|
||||
private TaskInfo taskInfo = new TaskInfo();
|
||||
|
||||
/**
|
||||
* 任务项
|
||||
*/
|
||||
@Valid
|
||||
private List<TaskItem> taskItems;
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package io.metersphere.sdk.dto.api.task;
|
||||
|
||||
import io.metersphere.sdk.dto.api.result.MsRegexDTO;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 任务请求参数数据
|
||||
*/
|
||||
@Data
|
||||
public class TaskInfo implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
private String msUrl;
|
||||
private String kafkaConfig;
|
||||
private String minioConfig;
|
||||
private int poolSize;
|
||||
/**
|
||||
* 批量执行时的队列ID
|
||||
*/
|
||||
private String queueId;
|
||||
/**
|
||||
* 是否需要实时接收单个步骤的结果
|
||||
*/
|
||||
private Boolean realTime = false;
|
||||
/**
|
||||
* 是否保存执行结果
|
||||
*/
|
||||
private Boolean saveResult = true;
|
||||
/**
|
||||
* 是否需要解析脚本
|
||||
* 接口详情页面,需要传试试详情,会其他解析脚本,needParseScript 为 false
|
||||
* 不传详情执行时,通过 task-runner 发起解析脚本请求,needParseScript 为 true
|
||||
*/
|
||||
private Boolean needParseScript = true;
|
||||
/**
|
||||
* 操作人
|
||||
*/
|
||||
private String userId;
|
||||
/**
|
||||
* 触发方式
|
||||
* 手动执行,批量执行,API执行,定时任务
|
||||
* {@link io.metersphere.sdk.constants.TaskTriggerMode}
|
||||
*/
|
||||
private String triggerMode;
|
||||
/**
|
||||
* 资源类型
|
||||
*
|
||||
* @see io.metersphere.sdk.constants.ApiExecuteResourceType
|
||||
*/
|
||||
private String resourceType;
|
||||
|
||||
/**
|
||||
* 当前项目执行时所需的资源
|
||||
*/
|
||||
private TaskProjectResource projectResource = new TaskProjectResource();
|
||||
|
||||
/**
|
||||
* 误报规则
|
||||
*/
|
||||
private List<MsRegexDTO> msRegexList;
|
||||
/**
|
||||
* 项目id
|
||||
*/
|
||||
@NotBlank
|
||||
private String projectId;
|
||||
|
||||
/**
|
||||
* {@link io.metersphere.sdk.constants.ApiExecuteRunMode}
|
||||
*/
|
||||
@NotBlank
|
||||
private String runMode;
|
||||
|
||||
/**
|
||||
* 运行配置
|
||||
*/
|
||||
@Valid
|
||||
private ApiRunModeConfigDTO runModeConfig = new ApiRunModeConfigDTO();
|
||||
|
||||
/**
|
||||
* 记录执行时的环境变量
|
||||
*/
|
||||
private List<String> environmentVariables;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package io.metersphere.sdk.dto.api.task;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 任务项
|
||||
*/
|
||||
@Data
|
||||
public class TaskItem implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@NotBlank
|
||||
private String reportId;
|
||||
/**
|
||||
* 执行的资源ID
|
||||
*/
|
||||
@NotBlank
|
||||
private String resourceId;
|
||||
/**
|
||||
* 待执行任务所需要的文件资源
|
||||
*/
|
||||
private TaskResourceFile taskResourceFile = new TaskResourceFile();
|
||||
/**
|
||||
* 场景执行时关联的其他项目的步骤所需的资源
|
||||
*/
|
||||
private TaskProjectResource refProjectResource = new TaskProjectResource();
|
||||
/**
|
||||
* 要执行的请求总量,用于计算执行各种指标
|
||||
*/
|
||||
private Long requestCount;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package io.metersphere.sdk.dto.api.task;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/**
|
||||
* 任务项
|
||||
*/
|
||||
@Data
|
||||
public class TaskProjectResource implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 插件文件列表
|
||||
* id 为插件的 id + 更新时间戳
|
||||
* 任务中心批量执行时会有并发操作,使用 CopyOnWriteArrayList
|
||||
*/
|
||||
private CopyOnWriteArrayList<ApiExecuteFileInfo> pluginFiles;
|
||||
|
||||
/**
|
||||
* 接口测试函数包
|
||||
*/
|
||||
private CopyOnWriteArrayList<ApiExecuteFileInfo> funcJars;
|
||||
}
|
|
@ -1,13 +1,10 @@
|
|||
package io.metersphere.sdk.dto.api.task;
|
||||
|
||||
import io.metersphere.sdk.dto.api.result.MsRegexDTO;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 任务请求参数数据
|
||||
|
@ -17,97 +14,15 @@ public class TaskRequestDTO implements Serializable {
|
|||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@NotBlank
|
||||
private String reportId;
|
||||
private String msUrl;
|
||||
private String kafkaConfig;
|
||||
private String minioConfig;
|
||||
private int poolSize;
|
||||
/**
|
||||
* 批量执行时的队列ID
|
||||
*/
|
||||
private String queueId;
|
||||
/**
|
||||
* 是否需要实时接收单个步骤的结果
|
||||
*/
|
||||
private Boolean realTime = false;
|
||||
/**
|
||||
* 是否保存执行结果
|
||||
*/
|
||||
private Boolean saveResult = true;
|
||||
/**
|
||||
* 执行的资源ID
|
||||
*/
|
||||
@NotBlank
|
||||
private String resourceId;
|
||||
/**
|
||||
* 触发方式
|
||||
* 手动执行,批量执行,API执行,定时任务
|
||||
* {@link io.metersphere.sdk.constants.TaskTriggerMode}
|
||||
*/
|
||||
private String triggerMode;
|
||||
/**
|
||||
* 资源类型
|
||||
*
|
||||
* @see io.metersphere.sdk.constants.ApiExecuteResourceType
|
||||
*/
|
||||
private String resourceType;
|
||||
/**
|
||||
* 点击调试时,尚未保存的本地上传的文件列表
|
||||
*/
|
||||
private List<ApiExecuteFileInfo> localTempFiles;
|
||||
/**
|
||||
* 通过本地上传的文件ID列表
|
||||
*/
|
||||
private List<ApiExecuteFileInfo> localFiles;
|
||||
/**
|
||||
* 关联文件管理的文件列表
|
||||
* 这里记录文件名,mino存的文件名是id
|
||||
* 执行时下载文件后,按原文件命名
|
||||
*/
|
||||
private List<ApiExecuteFileInfo> refFiles;
|
||||
/**
|
||||
* 插件文件列表
|
||||
* id 为插件的 id + 更新时间戳
|
||||
*/
|
||||
private List<ApiExecuteFileInfo> pluginFiles;
|
||||
|
||||
/**
|
||||
* 接口测试函数包
|
||||
*/
|
||||
private List<ApiExecuteFileInfo> funcJars;
|
||||
|
||||
/**
|
||||
* 误报规则
|
||||
*/
|
||||
List<MsRegexDTO> msRegexList;
|
||||
/**
|
||||
* 项目id
|
||||
*/
|
||||
@NotBlank
|
||||
private String projectId;
|
||||
|
||||
/**
|
||||
* {@link io.metersphere.sdk.constants.ApiExecuteRunMode}
|
||||
*/
|
||||
@NotBlank
|
||||
private String runMode;
|
||||
|
||||
/**
|
||||
* 运行配置
|
||||
* 任务的基本信息
|
||||
*/
|
||||
@Valid
|
||||
private ApiRunModeConfigDTO runModeConfig = new ApiRunModeConfigDTO();
|
||||
private TaskInfo taskInfo = new TaskInfo();
|
||||
|
||||
/**
|
||||
* TODO 要执行的请求总量,用于计算执行各种指标
|
||||
* 任务项
|
||||
*/
|
||||
private Long requestCount;
|
||||
|
||||
/**
|
||||
* 记录执行时的环境变量
|
||||
*/
|
||||
private List<String> environmentVariables;
|
||||
|
||||
// TODO 其它执行参数
|
||||
@Valid
|
||||
private TaskItem taskItem;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
package io.metersphere.sdk.dto.api.task;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2024-06-03 16:06
|
||||
*/
|
||||
@Data
|
||||
public class TaskResourceFile implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* 点击调试时,尚未保存的本地上传的文件列表
|
||||
*/
|
||||
private List<ApiExecuteFileInfo> localTempFiles;
|
||||
/**
|
||||
* 通过本地上传的文件ID列表
|
||||
*/
|
||||
private List<ApiExecuteFileInfo> localFiles;
|
||||
/**
|
||||
* 关联文件管理的文件列表
|
||||
* 这里记录文件名,mino存的文件名是id
|
||||
* 执行时下载文件后,按原文件命名
|
||||
*/
|
||||
private List<ApiExecuteFileInfo> refFiles;
|
||||
}
|
|
@ -1,21 +1,16 @@
|
|||
package io.metersphere.api.controller;
|
||||
|
||||
import io.metersphere.api.service.ApiExecuteResourceService;
|
||||
import io.metersphere.api.service.ApiExecuteService;
|
||||
import io.metersphere.api.service.definition.ApiReportService;
|
||||
import io.metersphere.api.service.scenario.ApiScenarioReportService;
|
||||
import io.metersphere.sdk.constants.ExecStatus;
|
||||
import io.metersphere.sdk.dto.api.task.GetRunScriptRequest;
|
||||
import io.metersphere.sdk.dto.api.task.GetRunScriptResult;
|
||||
import io.metersphere.sdk.file.FileRequest;
|
||||
import io.metersphere.sdk.util.LogUtils;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2023-12-05 17:52
|
||||
|
@ -24,15 +19,10 @@ import java.util.Optional;
|
|||
@RequestMapping("/api/execute/resource")
|
||||
@Tag(name = "接口测试-执行-资源")
|
||||
public class ApiExecuteResourceController {
|
||||
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
@Resource
|
||||
private ApiExecuteService apiExecuteService;
|
||||
@Resource
|
||||
private ApiReportService apiReportService;
|
||||
@Resource
|
||||
private ApiScenarioReportService apiScenarioReportService;
|
||||
private ApiExecuteResourceService apiExecuteResourceService;
|
||||
|
||||
/**
|
||||
* 获取执行脚本
|
||||
|
@ -44,13 +34,18 @@ public class ApiExecuteResourceController {
|
|||
@GetMapping("script")
|
||||
@Operation(summary = "获取执行脚本")
|
||||
public String getScript(@RequestParam("reportId") String reportId, @RequestParam("testId") String testId) {
|
||||
String key = apiExecuteService.getScriptRedisKey(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);
|
||||
return apiExecuteResourceService.getRunScript(reportId, testId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取执行脚本
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("script")
|
||||
@Operation(summary = "获取执行脚本")
|
||||
public GetRunScriptResult getScript(@RequestBody GetRunScriptRequest request) {
|
||||
return apiExecuteResourceService.getRunScript(request);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,6 +14,7 @@ import io.metersphere.api.service.ApiFileResourceService;
|
|||
import io.metersphere.api.service.ApiValidateService;
|
||||
import io.metersphere.api.service.scenario.ApiScenarioLogService;
|
||||
import io.metersphere.api.service.scenario.ApiScenarioNoticeService;
|
||||
import io.metersphere.api.service.scenario.ApiScenarioRunService;
|
||||
import io.metersphere.api.service.scenario.ApiScenarioService;
|
||||
import io.metersphere.project.service.FileModuleService;
|
||||
import io.metersphere.sdk.constants.PermissionConstants;
|
||||
|
@ -49,6 +50,8 @@ public class ApiScenarioController {
|
|||
@Resource
|
||||
private ApiScenarioService apiScenarioService;
|
||||
@Resource
|
||||
private ApiScenarioRunService apiScenarioRunService;
|
||||
@Resource
|
||||
private ApiValidateService apiValidateService;
|
||||
@Resource
|
||||
private FileModuleService fileModuleService;
|
||||
|
@ -166,14 +169,14 @@ public class ApiScenarioController {
|
|||
@Operation(summary = "接口测试-接口场景管理-场景调试")
|
||||
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_EXECUTE)
|
||||
public TaskRequestDTO debug(@Validated @RequestBody ApiScenarioDebugRequest request) {
|
||||
return apiScenarioService.debug(request);
|
||||
return apiScenarioRunService.debug(request);
|
||||
}
|
||||
|
||||
@PostMapping("/run")
|
||||
@Operation(summary = "接口测试-接口场景管理-场景执行")
|
||||
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_EXECUTE)
|
||||
public TaskRequestDTO run(@Validated @RequestBody ApiScenarioDebugRequest request) {
|
||||
return apiScenarioService.run(request, SessionUtils.getUserId());
|
||||
return apiScenarioRunService.run(request, SessionUtils.getUserId());
|
||||
}
|
||||
|
||||
@GetMapping("/run/{id}")
|
||||
|
@ -181,7 +184,7 @@ public class ApiScenarioController {
|
|||
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_EXECUTE)
|
||||
@CheckOwner(resourceId = "#id", resourceType = "api_scenario")
|
||||
public TaskRequestDTO run(@PathVariable String id, @RequestParam(required = false) String reportId) {
|
||||
return apiScenarioService.run(id, reportId, SessionUtils.getUserId());
|
||||
return apiScenarioRunService.run(id, reportId, SessionUtils.getUserId());
|
||||
}
|
||||
|
||||
@GetMapping(value = "/update-status/{id}/{status}")
|
||||
|
|
|
@ -8,11 +8,13 @@ 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.ApiExecuteService;
|
||||
import io.metersphere.api.service.scenario.ApiScenarioService;
|
||||
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.sdk.dto.api.task.ApiRunModeConfigDTO;
|
||||
import io.metersphere.sdk.dto.api.task.TaskInfo;
|
||||
import io.metersphere.sdk.dto.api.task.TaskItem;
|
||||
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
|
||||
import io.metersphere.sdk.util.CommonBeanFactory;
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
|
@ -27,17 +29,17 @@ import org.quartz.TriggerKey;
|
|||
public class ApiScenarioScheduleJob extends BaseScheduleJob {
|
||||
@Override
|
||||
protected void businessExecute(JobExecutionContext context) {
|
||||
ApiScenarioService apiScenarioService = CommonBeanFactory.getBean(ApiScenarioService.class);
|
||||
ApiExecuteService apiExecuteService = CommonBeanFactory.getBean(ApiExecuteService.class);
|
||||
ApiScenarioRunService apiScenarioRunService = CommonBeanFactory.getBean(ApiScenarioRunService.class);
|
||||
ApiRunModeConfigDTO apiRunModeConfigDTO = JSON.parseObject(context.getJobDetail().getJobDataMap().get("config").toString(), ApiRunModeConfigDTO.class);
|
||||
|
||||
ApiScenarioDetail apiScenarioDetail = apiScenarioService.getForRun(resourceId);
|
||||
ApiScenarioDetail apiScenarioDetail = apiScenarioRunService.getForRun(resourceId);
|
||||
if (apiScenarioDetail == null) {
|
||||
LogUtils.info("当前定时任务的场景已删除 {}", resourceId);
|
||||
return;
|
||||
}
|
||||
MsScenario msScenario = apiScenarioService.getMsScenario(apiScenarioDetail);
|
||||
ApiScenarioParseParam parseParam = apiScenarioService.getApiScenarioParseParam(apiScenarioDetail);
|
||||
MsScenario msScenario = apiScenarioRunService.getMsScenario(apiScenarioDetail);
|
||||
ApiScenarioParseParam parseParam = apiScenarioRunService.getApiScenarioParseParam(apiScenarioDetail);
|
||||
parseParam.setEnvironmentId(apiRunModeConfigDTO.getEnvironmentId());
|
||||
parseParam.setGrouped(apiRunModeConfigDTO.getGrouped());
|
||||
|
||||
|
@ -52,33 +54,35 @@ public class ApiScenarioScheduleJob extends BaseScheduleJob {
|
|||
|
||||
msScenario.setResourceId(apiScenarioDetail.getId());
|
||||
// 解析生成场景树,并保存临时变量
|
||||
ApiScenarioParseTmpParam tmpParam = apiScenarioService.parse(msScenario, apiScenarioDetail.getSteps(), parseParam);
|
||||
ApiScenarioParseTmpParam tmpParam = apiScenarioRunService.parse(msScenario, apiScenarioDetail.getSteps(), parseParam);
|
||||
|
||||
ApiResourceRunRequest runRequest = apiScenarioService.getApiResourceRunRequest(msScenario, tmpParam);
|
||||
ApiResourceRunRequest runRequest = apiScenarioRunService.getApiResourceRunRequest(msScenario, tmpParam);
|
||||
|
||||
TaskRequestDTO taskRequest = apiScenarioService.getTaskRequest(IDGenerator.nextStr(), apiScenarioDetail.getId(), apiScenarioDetail.getProjectId(), ApiExecuteRunMode.SCENARIO.name());
|
||||
taskRequest.getRunModeConfig().setPoolId(apiRunModeConfigDTO.getPoolId());
|
||||
taskRequest.setSaveResult(true);
|
||||
taskRequest.setRealTime(false);
|
||||
taskRequest.getRunModeConfig().setEnvironmentId(parseParam.getEnvironmentId());
|
||||
taskRequest.setRequestCount(tmpParam.getRequestCount().get());
|
||||
TaskRequestDTO taskRequest = apiScenarioRunService.getTaskRequest(IDGenerator.nextStr(), apiScenarioDetail.getId(), apiScenarioDetail.getProjectId(), ApiExecuteRunMode.SCENARIO.name());
|
||||
TaskInfo taskInfo = taskRequest.getTaskInfo();
|
||||
TaskItem taskItem = taskRequest.getTaskItem();
|
||||
taskInfo.getRunModeConfig().setPoolId(apiRunModeConfigDTO.getPoolId());
|
||||
taskInfo.setSaveResult(true);
|
||||
taskInfo.setRealTime(false);
|
||||
taskInfo.getRunModeConfig().setEnvironmentId(parseParam.getEnvironmentId());
|
||||
taskItem.setRequestCount(tmpParam.getRequestCount().get());
|
||||
|
||||
ApiScenarioParamConfig parseConfig = apiScenarioService.getApiScenarioParamConfig(parseParam, tmpParam.getScenarioParseEnvInfo());
|
||||
parseConfig.setReportId(taskRequest.getReportId());
|
||||
ApiScenarioParamConfig parseConfig = apiScenarioRunService.getApiScenarioParamConfig(msScenario.getProjectId(), parseParam, tmpParam.getScenarioParseEnvInfo());
|
||||
parseConfig.setReportId(taskItem.getReportId());
|
||||
|
||||
// 初始化报告
|
||||
ApiScenarioReport scenarioReport = apiScenarioService.getScenarioReport(userId);
|
||||
scenarioReport.setId(taskRequest.getReportId());
|
||||
ApiScenarioReport scenarioReport = apiScenarioRunService.getScenarioReport(userId);
|
||||
scenarioReport.setId(taskItem.getReportId());
|
||||
scenarioReport.setTriggerMode(TaskTriggerMode.SCHEDULE.name());
|
||||
scenarioReport.setRunMode(ApiBatchRunMode.PARALLEL.name());
|
||||
scenarioReport.setPoolId(apiRunModeConfigDTO.getPoolId());
|
||||
scenarioReport.setEnvironmentId(parseParam.getEnvironmentId());
|
||||
scenarioReport.setWaitingTime(apiScenarioService.getGlobalWaitTime(parseParam.getScenarioConfig()));
|
||||
scenarioReport.setWaitingTime(apiScenarioRunService.getGlobalWaitTime(parseParam.getScenarioConfig()));
|
||||
|
||||
apiScenarioService.initApiReport(apiScenarioDetail, scenarioReport);
|
||||
apiScenarioRunService.initApiReport(apiScenarioDetail, scenarioReport);
|
||||
|
||||
// 初始化报告步骤
|
||||
apiScenarioService.initScenarioReportSteps(apiScenarioDetail.getSteps(), taskRequest.getReportId());
|
||||
apiScenarioRunService.initScenarioReportSteps(apiScenarioDetail.getSteps(), taskItem.getReportId());
|
||||
|
||||
apiExecuteService.execute(runRequest, taskRequest, parseConfig);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
package io.metersphere.api.service;
|
||||
|
||||
import io.metersphere.api.service.definition.ApiReportService;
|
||||
import io.metersphere.api.service.definition.ApiTestCaseService;
|
||||
import io.metersphere.api.service.scenario.ApiScenarioReportService;
|
||||
import io.metersphere.api.service.scenario.ApiScenarioRunService;
|
||||
import io.metersphere.sdk.constants.ApiExecuteResourceType;
|
||||
import io.metersphere.sdk.constants.ExecStatus;
|
||||
import io.metersphere.sdk.dto.api.task.GetRunScriptRequest;
|
||||
import io.metersphere.sdk.dto.api.task.GetRunScriptResult;
|
||||
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 jakarta.annotation.Resource;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class ApiExecuteResourceService {
|
||||
|
||||
@Resource
|
||||
private ApiExecuteService apiExecuteService;
|
||||
@Resource
|
||||
private ApiReportService apiReportService;
|
||||
@Resource
|
||||
private ApiScenarioReportService apiScenarioReportService;
|
||||
@Resource
|
||||
private ApiScenarioRunService apiScenarioRunService;
|
||||
@Resource
|
||||
private ApiTestCaseService apiTestCaseService;
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
|
||||
public GetRunScriptResult getRunScript(GetRunScriptRequest request) {
|
||||
TaskItem taskItem = request.getTaskItem();
|
||||
String reportId = taskItem.getReportId();
|
||||
String key = apiExecuteService.getTaskKey(reportId, taskItem.getResourceId());
|
||||
LogUtils.info("生成并获取执行脚本: {}", key);
|
||||
|
||||
ApiExecuteResourceType apiExecuteResourceType = EnumValidator.validateEnum(ApiExecuteResourceType.class, request.getResourceType());
|
||||
switch (apiExecuteResourceType) {
|
||||
case API_SCENARIO -> {
|
||||
apiScenarioReportService.updateReportStatus(reportId, ExecStatus.RUNNING.name());
|
||||
return apiScenarioRunService.getRunScript(request);
|
||||
}
|
||||
case API_CASE -> {
|
||||
apiReportService.updateReportStatus(reportId, ExecStatus.RUNNING.name());
|
||||
return apiTestCaseService.getRunScript(request);
|
||||
}
|
||||
default -> throw new MSException("不支持的资源类型: " + request.getResourceType());
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -20,9 +20,7 @@ import io.metersphere.project.dto.environment.GlobalParams;
|
|||
import io.metersphere.project.dto.environment.GlobalParamsDTO;
|
||||
import io.metersphere.project.service.*;
|
||||
import io.metersphere.sdk.constants.*;
|
||||
import io.metersphere.sdk.dto.api.task.ApiExecuteFileInfo;
|
||||
import io.metersphere.sdk.dto.api.task.ApiRunModeConfigDTO;
|
||||
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
|
||||
import io.metersphere.sdk.dto.api.task.*;
|
||||
import io.metersphere.sdk.exception.MSException;
|
||||
import io.metersphere.sdk.exception.TaskRunnerResultCode;
|
||||
import io.metersphere.sdk.file.FileCenter;
|
||||
|
@ -56,6 +54,7 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -121,87 +120,75 @@ public class ApiExecuteService {
|
|||
}
|
||||
}
|
||||
|
||||
public String getScriptRedisKey(String reportId, String testId) {
|
||||
public String getTaskKey(String reportId, String testId) {
|
||||
return reportId + "_" + testId;
|
||||
}
|
||||
|
||||
public TaskRequestDTO execute(ApiResourceRunRequest runRequest, TaskRequestDTO taskRequest, ApiParamConfig parameterConfig) {
|
||||
// 置minio kafka ms 等信息
|
||||
setServerInfoParam(taskRequest);
|
||||
|
||||
// 设置执行文件参数
|
||||
setTaskFileParam(runRequest, taskRequest);
|
||||
|
||||
// 误报处理 todo 多项目
|
||||
taskRequest.setMsRegexList(projectApplicationService.get(Collections.singletonList(taskRequest.getProjectId())));
|
||||
|
||||
if (!StringUtils.equals(taskRequest.getResourceType(), ApiExecuteResourceType.API_DEBUG.name())) {
|
||||
// 设置全局参数,接口调试不使用全局参数
|
||||
parameterConfig.setGlobalParams(getGlobalParam(taskRequest.getProjectId()));
|
||||
}
|
||||
TaskInfo taskInfo = taskRequest.getTaskInfo();
|
||||
TaskItem taskItem = taskRequest.getTaskItem();
|
||||
|
||||
// 解析执行脚本
|
||||
String executeScript = parseExecuteScript(runRequest.getTestElement(), parameterConfig);
|
||||
|
||||
// 设置插件文件信息 todo 多项目
|
||||
List<ApiExecuteFileInfo> pluginFiles = new ArrayList<>();
|
||||
pluginFiles.addAll(apiPluginService.getFileInfoByProjectId(taskRequest.getProjectId()));
|
||||
pluginFiles.addAll(jdbcDriverPluginService.getFileInfoByProjectId(taskRequest.getProjectId()));
|
||||
|
||||
taskRequest.setPluginFiles(pluginFiles);
|
||||
// 脚本已经解析,不需要再解析
|
||||
taskInfo.setNeedParseScript(false);
|
||||
|
||||
// 将测试脚本缓存到 redis
|
||||
String scriptRedisKey = getScriptRedisKey(taskRequest.getReportId(), taskRequest.getResourceId());
|
||||
String scriptRedisKey = getTaskKey(taskItem.getReportId(), taskItem.getResourceId());
|
||||
stringRedisTemplate.opsForValue().set(scriptRedisKey, executeScript, 1, TimeUnit.DAYS);
|
||||
|
||||
if (StringUtils.equals(taskRequest.getRunMode(), ApiExecuteRunMode.FRONTEND_DEBUG.name())) {
|
||||
setTaskItemFileParam(runRequest, taskItem);
|
||||
|
||||
if (StringUtils.equals(taskInfo.getRunMode(), ApiExecuteRunMode.FRONTEND_DEBUG.name())) {
|
||||
taskInfo = setTaskRequestParams(taskInfo);
|
||||
// 清空mino和kafka配置信息,避免前端获取
|
||||
taskRequest.setMinioConfig(null);
|
||||
taskRequest.setKafkaConfig(null);
|
||||
taskInfo.setMinioConfig(null);
|
||||
taskInfo.setKafkaConfig(null);
|
||||
// 前端调试返回执行参数,由前端调用本地资源池执行
|
||||
return taskRequest;
|
||||
}
|
||||
|
||||
try {
|
||||
return doExecute(taskRequest);
|
||||
} catch (HttpServerErrorException e) {
|
||||
handleDoExecuteException(scriptRedisKey, e);
|
||||
int errorCode = e.getResponseBodyAs(ResultHolder.class).getCode();
|
||||
for (TaskRunnerResultCode taskRunnerResultCode : TaskRunnerResultCode.values()) {
|
||||
// 匹配资源池的错误代码,抛出相应异常
|
||||
if (taskRunnerResultCode.getCode() == errorCode) {
|
||||
throw new MSException(taskRunnerResultCode, e.getMessage());
|
||||
}
|
||||
}
|
||||
throw new MSException(RESOURCE_POOL_EXECUTE_ERROR, e.getMessage());
|
||||
} catch (MSException e) {
|
||||
handleDoExecuteException(scriptRedisKey, e);
|
||||
// 集合报告对应的资源池集合移除
|
||||
removeCollectionReport(taskRequest);
|
||||
throw e;
|
||||
return execute(taskRequest);
|
||||
} catch (Exception e) {
|
||||
handleDoExecuteException(scriptRedisKey, e);
|
||||
// 集合报告对应的资源池集合移除
|
||||
removeCollectionReport(taskRequest);
|
||||
throw new MSException(RESOURCE_POOL_EXECUTE_ERROR, e.getMessage());
|
||||
// 调用失败清理脚本
|
||||
stringRedisTemplate.delete(scriptRedisKey);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleDoExecuteException(String scriptRedisKey, Exception e) {
|
||||
LogUtils.error(e);
|
||||
// 调用失败清理脚本
|
||||
stringRedisTemplate.delete(scriptRedisKey);
|
||||
private TaskInfo setTaskRequestParams(TaskInfo taskInfo) {
|
||||
// 置minio kafka ms 等信息
|
||||
setServerInfoParam(taskInfo);
|
||||
// 设置项目执行所需要的文件信息
|
||||
setProjectTaskFileParam(taskInfo);
|
||||
|
||||
// 误报处理
|
||||
taskInfo.setMsRegexList(projectApplicationService.get(Collections.singletonList(taskInfo.getProjectId())));
|
||||
|
||||
return taskInfo;
|
||||
}
|
||||
/**
|
||||
* 给 taskRequest 设置当前项目相关的文件信息
|
||||
*
|
||||
* @param taskInfo 执行参数
|
||||
*/
|
||||
private void setProjectTaskFileParam(TaskInfo taskInfo) {
|
||||
// 设置jar包信息
|
||||
setTaskFuncJarParam(taskInfo);
|
||||
// 设置插件文件信息
|
||||
setProjectPluginParam(taskInfo);
|
||||
}
|
||||
|
||||
private void removeCollectionReport(TaskRequestDTO taskRequest) {
|
||||
// 集合报告对应的资源池集合移除
|
||||
if (taskRequest.getRunModeConfig().getIntegratedReport()) {
|
||||
String SET_PREFIX = "set:" + taskRequest.getRunModeConfig().getCollectionReport().getReportId();
|
||||
stringRedisTemplate.opsForSet().remove(SET_PREFIX, taskRequest.getResourceId());
|
||||
}
|
||||
private void setProjectPluginParam(TaskInfo taskInfo) {
|
||||
// 设置插件文件信息
|
||||
CopyOnWriteArrayList<ApiExecuteFileInfo> pluginFiles = new CopyOnWriteArrayList<>();
|
||||
pluginFiles.addAll(apiPluginService.getFileInfoByProjectId(taskInfo.getProjectId()));
|
||||
pluginFiles.addAll(jdbcDriverPluginService.getFileInfoByProjectId(taskInfo.getProjectId()));
|
||||
taskInfo.getProjectResource().setPluginFiles(pluginFiles);
|
||||
}
|
||||
|
||||
private GlobalParams getGlobalParam(String projectId) {
|
||||
public GlobalParams getGlobalParam(String projectId) {
|
||||
GlobalParamsDTO globalParamsDTO = globalParamsService.get(projectId);
|
||||
if (globalParamsDTO != null) {
|
||||
return globalParamsDTO.getGlobalParams();
|
||||
|
@ -214,37 +201,110 @@ public class ApiExecuteService {
|
|||
*
|
||||
* @param taskRequest 执行参数
|
||||
*/
|
||||
private TaskRequestDTO doExecute(TaskRequestDTO taskRequest) throws Exception {
|
||||
// 获取资源池
|
||||
TestResourcePoolReturnDTO testResourcePoolDTO = getGetResourcePoolNodeDTO(taskRequest.getRunModeConfig(), taskRequest.getProjectId());
|
||||
if (testResourcePoolDTO == null || CollectionUtils.isEmpty(testResourcePoolDTO.getTestResourceReturnDTO().getNodesList())) {
|
||||
throw new MSException(ApiResultCode.EXECUTE_RESOURCE_POOL_NOT_CONFIG);
|
||||
}
|
||||
TestResourceNodeDTO testResourceNodeDTO = getProjectExecuteNode(testResourcePoolDTO);
|
||||
public TaskRequestDTO execute(TaskRequestDTO taskRequest) {
|
||||
TaskInfo taskInfo = taskRequest.getTaskInfo();
|
||||
TaskItem taskItem = taskRequest.getTaskItem();
|
||||
|
||||
if (StringUtils.isNotBlank(testResourcePoolDTO.getServerUrl())) {
|
||||
// 如果资源池配置了当前站点,则使用资源池的
|
||||
taskRequest.setMsUrl(testResourcePoolDTO.getServerUrl());
|
||||
}
|
||||
taskRequest.setPoolSize(testResourceNodeDTO.getConcurrentNumber());
|
||||
try {
|
||||
|
||||
String endpoint = TaskRunnerClient.getEndpoint(testResourceNodeDTO.getIp(), testResourceNodeDTO.getPort());
|
||||
LogUtils.info("开始发送请求【 {}_{} 】到 {} 节点执行", taskRequest.getReportId(), taskRequest.getResourceId(), endpoint);
|
||||
if (StringUtils.equalsAny(taskRequest.getRunMode(), ApiExecuteRunMode.FRONTEND_DEBUG.name(), ApiExecuteRunMode.BACKEND_DEBUG.name())) {
|
||||
TaskRunnerClient.debugApi(endpoint, taskRequest);
|
||||
} else {
|
||||
TaskRunnerClient.runApi(endpoint, taskRequest);
|
||||
taskInfo = setTaskRequestParams(taskInfo);
|
||||
|
||||
// 获取资源池
|
||||
TestResourcePoolReturnDTO testResourcePoolDTO = getGetResourcePoolNodeDTO(taskInfo.getRunModeConfig(), taskInfo.getProjectId());
|
||||
|
||||
TestResourceNodeDTO testResourceNodeDTO = getNextExecuteNode(testResourcePoolDTO);
|
||||
|
||||
if (StringUtils.isNotBlank(testResourcePoolDTO.getServerUrl())) {
|
||||
// 如果资源池配置了当前站点,则使用资源池的
|
||||
taskInfo.setMsUrl(testResourcePoolDTO.getServerUrl());
|
||||
}
|
||||
taskInfo.setPoolSize(testResourceNodeDTO.getConcurrentNumber());
|
||||
String endpoint = TaskRunnerClient.getEndpoint(testResourceNodeDTO.getIp(), testResourceNodeDTO.getPort());
|
||||
LogUtils.info("开始发送请求【 {}_{} 】到 {} 节点执行", taskItem.getReportId(), taskItem.getResourceId(), endpoint);
|
||||
if (StringUtils.equalsAny(taskInfo.getRunMode(), ApiExecuteRunMode.FRONTEND_DEBUG.name(), ApiExecuteRunMode.BACKEND_DEBUG.name())) {
|
||||
TaskRunnerClient.debugApi(endpoint, taskRequest);
|
||||
} else {
|
||||
TaskRunnerClient.runApi(endpoint, taskRequest);
|
||||
}
|
||||
|
||||
} catch (HttpServerErrorException e) {
|
||||
LogUtils.error(e);
|
||||
int errorCode = e.getResponseBodyAs(ResultHolder.class).getCode();
|
||||
for (TaskRunnerResultCode taskRunnerResultCode : TaskRunnerResultCode.values()) {
|
||||
// 匹配资源池的错误代码,抛出相应异常
|
||||
if (taskRunnerResultCode.getCode() == errorCode) {
|
||||
throw new MSException(taskRunnerResultCode, e.getMessage());
|
||||
}
|
||||
}
|
||||
throw new MSException(RESOURCE_POOL_EXECUTE_ERROR, e.getMessage());
|
||||
} catch (MSException e) {
|
||||
LogUtils.error(e);
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
LogUtils.error(e);
|
||||
throw new MSException(RESOURCE_POOL_EXECUTE_ERROR, e.getMessage());
|
||||
}
|
||||
|
||||
// 清空mino和kafka配置信息,避免前端获取
|
||||
taskRequest.setMinioConfig(null);
|
||||
taskRequest.setKafkaConfig(null);
|
||||
taskInfo.setMinioConfig(null);
|
||||
taskInfo.setKafkaConfig(null);
|
||||
|
||||
return taskRequest;
|
||||
|
||||
}
|
||||
|
||||
private TestResourceNodeDTO getProjectExecuteNode(TestResourcePoolReturnDTO resourcePoolDTO) {
|
||||
/**
|
||||
* 发送执行任务
|
||||
*
|
||||
*/
|
||||
public void batchExecute(TaskBatchRequestDTO taskRequest) {
|
||||
setTaskRequestParams(taskRequest.getTaskInfo());
|
||||
|
||||
TaskInfo taskInfo = taskRequest.getTaskInfo();
|
||||
// 获取资源池
|
||||
TestResourcePoolReturnDTO testResourcePool = getGetResourcePoolNodeDTO(taskInfo.getRunModeConfig(), taskInfo.getProjectId());
|
||||
|
||||
if (StringUtils.isNotBlank(testResourcePool.getServerUrl())) {
|
||||
// 如果资源池配置了当前站点,则使用资源池的
|
||||
taskInfo.setMsUrl(testResourcePool.getServerUrl());
|
||||
}
|
||||
|
||||
// 将任务按资源池的数量拆分
|
||||
List<TestResourceNodeDTO> nodesList = testResourcePool.getTestResourceReturnDTO().getNodesList();
|
||||
List<TaskBatchRequestDTO> distributeTasks = new ArrayList<>(nodesList.size());
|
||||
for (int i = 0; i < taskRequest.getTaskItems().size(); i++) {
|
||||
TaskBatchRequestDTO distributeTask;
|
||||
int nodeIndex = i % nodesList.size();
|
||||
if (distributeTasks.size() < nodesList.size()) {
|
||||
distributeTask = BeanUtils.copyBean(new TaskBatchRequestDTO(), taskRequest);
|
||||
distributeTask.setTaskItems(new ArrayList<>());
|
||||
distributeTasks.add(distributeTask);
|
||||
} else {
|
||||
distributeTask = distributeTasks.get(nodeIndex);
|
||||
}
|
||||
distributeTask.getTaskInfo().setPoolSize(nodesList.get(nodeIndex).getConcurrentNumber());
|
||||
distributeTask.getTaskItems().add(taskRequest.getTaskItems().get(i));
|
||||
}
|
||||
|
||||
for (int i = 0; i < nodesList.size(); i++) {
|
||||
// todo 优化某个资源池不可用的情况,以及清理 executionSet
|
||||
TestResourceNodeDTO testResourceNode = nodesList.get(i);
|
||||
TaskBatchRequestDTO subTaskRequest = distributeTasks.get(i);
|
||||
String endpoint = TaskRunnerClient.getEndpoint(testResourceNode.getIp(), testResourceNode.getPort());
|
||||
try {
|
||||
List<String> taskKeys = subTaskRequest.getTaskItems().stream()
|
||||
.map(taskItem -> taskItem.getReportId() + "_" + taskItem.getResourceId())
|
||||
.toList();
|
||||
LogUtils.info("开始发送批量任务到 {} 节点执行:\n" + taskKeys, endpoint);
|
||||
|
||||
TaskRunnerClient.batchRunApi(endpoint, subTaskRequest);
|
||||
} catch (Exception e) {
|
||||
LogUtils.error("发送批量任务到 {} 节点执行失败", endpoint);
|
||||
LogUtils.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private TestResourceNodeDTO getNextExecuteNode(TestResourcePoolReturnDTO resourcePoolDTO) {
|
||||
roundRobinService.initializeNodes(resourcePoolDTO.getId(), resourcePoolDTO.getTestResourceReturnDTO().getNodesList());
|
||||
try {
|
||||
TestResourceNodeDTO node = roundRobinService.getNextNode(resourcePoolDTO.getId());
|
||||
|
@ -263,18 +323,23 @@ public class ApiExecuteService {
|
|||
if (StringUtils.isBlank(poolId)) {
|
||||
poolId = getProjectApiResourcePoolId(projectId);
|
||||
}
|
||||
return getAvailableResourcePoolDTO(projectId, poolId);
|
||||
TestResourcePoolReturnDTO resourcePool = getAvailableResourcePoolDTO(projectId, poolId);
|
||||
|
||||
if (resourcePool == null || CollectionUtils.isEmpty(resourcePool.getTestResourceReturnDTO().getNodesList())) {
|
||||
throw new MSException(ApiResultCode.EXECUTE_RESOURCE_POOL_NOT_CONFIG);
|
||||
}
|
||||
return resourcePool;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置minio kafka ms 等信息
|
||||
*
|
||||
* @param taskRequest 执行参数
|
||||
* @param taskInfo 执行参数
|
||||
*/
|
||||
private void setServerInfoParam(TaskRequestDTO taskRequest) {
|
||||
taskRequest.setKafkaConfig(EncryptUtils.aesEncrypt(JSON.toJSONString(KafkaConfig.getKafkaConfig())));
|
||||
taskRequest.setMinioConfig(EncryptUtils.aesEncrypt(JSON.toJSONString(getMinio())));
|
||||
taskRequest.setMsUrl(systemParameterService.getBaseInfo().getUrl());
|
||||
private void setServerInfoParam(TaskInfo taskInfo) {
|
||||
taskInfo.setKafkaConfig(EncryptUtils.aesEncrypt(JSON.toJSONString(KafkaConfig.getKafkaConfig())));
|
||||
taskInfo.setMinioConfig(EncryptUtils.aesEncrypt(JSON.toJSONString(getMinio())));
|
||||
taskInfo.setMsUrl(systemParameterService.getBaseInfo().getUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -305,11 +370,12 @@ public class ApiExecuteService {
|
|||
|
||||
// 设置执行参数
|
||||
TaskRequestDTO taskRequest = getTaskRequest(reportId, testId, runRequest.getProjectId());
|
||||
setServerInfoParam(taskRequest);
|
||||
taskRequest.setRealTime(true);
|
||||
taskRequest.setSaveResult(false);
|
||||
taskRequest.setResourceType(ApiExecuteResourceType.API_DEBUG.name());
|
||||
taskRequest.setRunMode(ApiExecuteRunMode.BACKEND_DEBUG.name());
|
||||
TaskInfo taskInfo = taskRequest.getTaskInfo();
|
||||
setServerInfoParam(taskInfo);
|
||||
taskInfo.setRealTime(true);
|
||||
taskInfo.setSaveResult(false);
|
||||
taskInfo.setResourceType(ApiExecuteResourceType.API_DEBUG.name());
|
||||
taskInfo.setRunMode(ApiExecuteRunMode.BACKEND_DEBUG.name());
|
||||
|
||||
return execute(apiRunRequest, taskRequest, new ApiParamConfig());
|
||||
}
|
||||
|
@ -318,57 +384,77 @@ public class ApiExecuteService {
|
|||
* 给 taskRequest 设置文件相关参数
|
||||
*
|
||||
* @param runRequest 请求参数
|
||||
* @param taskRequest 执行参数
|
||||
*/
|
||||
private void setTaskFileParam(ApiResourceRunRequest runRequest, TaskRequestDTO taskRequest) {
|
||||
setTaskRefFileParam(runRequest, taskRequest);
|
||||
setTaskTmpFileParam(runRequest, taskRequest);
|
||||
setTaskFuncJarParam(runRequest, taskRequest);
|
||||
public void setTaskItemFileParam(ApiResourceRunRequest runRequest, TaskItem taskItem) {
|
||||
// 接口执行相关的文件
|
||||
setTaskRefFileParam(runRequest, taskItem.getTaskResourceFile(), taskItem.getResourceId());
|
||||
// 调试时未保存的文件
|
||||
setTaskTmpFileParam(runRequest, taskItem.getTaskResourceFile());
|
||||
// 场景引用跨项目的用例所需要的jar包
|
||||
setTaskFuncJarParam(taskItem, runRequest.getRefProjectIds().stream().toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 给 taskRequest 设置文件相关参数
|
||||
*/
|
||||
public void setTaskItemFileParam(TaskItem taskItem) {
|
||||
setTaskItemFileParam(new ApiResourceRunRequest(), taskItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理脚本执行所需要的jar包
|
||||
*
|
||||
* @param runRequest
|
||||
* @param taskRequest
|
||||
* @param taskInfo
|
||||
*/
|
||||
private void setTaskFuncJarParam(ApiResourceRunRequest runRequest, TaskRequestDTO taskRequest) {
|
||||
Set<String> projectIdsSet = runRequest.getRefProjectIds();
|
||||
projectIdsSet.add(taskRequest.getProjectId());
|
||||
List<String> projectIds = projectIdsSet.stream().collect(Collectors.toList());
|
||||
|
||||
private void setTaskFuncJarParam(TaskInfo taskInfo) {
|
||||
// 获取函数jar包
|
||||
List<FileMetadata> fileMetadataList = fileManagementService.findJarByProjectId(projectIds);
|
||||
taskRequest.setFuncJars(getApiExecuteFileInfo(fileMetadataList));
|
||||
List<FileMetadata> fileMetadataList = fileManagementService.findJarByProjectId(List.of(taskInfo.getProjectId()));
|
||||
taskInfo.getProjectResource().setFuncJars(getApiExecuteFileInfo(fileMetadataList));
|
||||
|
||||
// TODO 当前项目没有包分两种情况,1 之前存在被删除,2 一直不存在
|
||||
// 为了兼容1 这种情况需要初始化一条空的数据,由执行机去做卸载
|
||||
if (CollectionUtils.isEmpty(taskRequest.getFuncJars())) {
|
||||
if (CollectionUtils.isEmpty(taskInfo.getProjectResource().getFuncJars())) {
|
||||
ApiExecuteFileInfo tempFileInfo = new ApiExecuteFileInfo();
|
||||
tempFileInfo.setProjectId(taskRequest.getProjectId());
|
||||
taskRequest.setFuncJars(List.of(tempFileInfo));
|
||||
tempFileInfo.setProjectId(taskInfo.getProjectId());
|
||||
CopyOnWriteArrayList copyOnWriteArrayList = new CopyOnWriteArrayList();
|
||||
copyOnWriteArrayList.add(tempFileInfo);
|
||||
taskInfo.getProjectResource().setFuncJars(copyOnWriteArrayList);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理脚本执行所需要的jar包
|
||||
*
|
||||
* @param taskItem
|
||||
*/
|
||||
private void setTaskFuncJarParam(TaskItem taskItem, List<String> projectIds) {
|
||||
if (CollectionUtils.isEmpty(projectIds)) {
|
||||
return;
|
||||
}
|
||||
TaskProjectResource projectResource = taskItem.getRefProjectResource();
|
||||
// 获取函数jar包
|
||||
List<FileMetadata> fileMetadataList = fileManagementService.findJarByProjectId(projectIds);
|
||||
projectResource.setFuncJars(getApiExecuteFileInfo(fileMetadataList));
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理没有保存的临时文件
|
||||
*
|
||||
* @param runRequest
|
||||
* @param taskRequest
|
||||
*/
|
||||
private void setTaskTmpFileParam(ApiResourceRunRequest runRequest, TaskRequestDTO taskRequest) {
|
||||
private void setTaskTmpFileParam(ApiResourceRunRequest runRequest, TaskResourceFile taskResourceFile) {
|
||||
// 没有保存的本地临时文件
|
||||
List<String> uploadFileIds = runRequest.getUploadFileIds();
|
||||
if (CollectionUtils.isNotEmpty(uploadFileIds)) {
|
||||
List<ApiExecuteFileInfo> localTempFiles = uploadFileIds.stream()
|
||||
.map(tempFileId -> {
|
||||
String fileName = apiFileResourceService.getTempFileNameByFileId(tempFileId);
|
||||
return getApiExecuteFileInfo(tempFileId, fileName, taskRequest.getProjectId());
|
||||
return getApiExecuteFileInfo(tempFileId, fileName, null);
|
||||
})
|
||||
// uploadFileIds 查不到,则已经移动到正式目录
|
||||
.filter(i -> StringUtils.isNotBlank(i.getFileName()))
|
||||
.collect(Collectors.toList());
|
||||
taskRequest.setLocalTempFiles(localTempFiles);
|
||||
taskResourceFile.setLocalTempFiles(localTempFiles);
|
||||
}
|
||||
|
||||
List<String> linkFileIds = runRequest.getLinkFileIds();
|
||||
|
@ -376,7 +462,7 @@ public class ApiExecuteService {
|
|||
if (CollectionUtils.isNotEmpty(linkFileIds)) {
|
||||
List<FileMetadata> fileMetadataList = fileMetadataService.getByFileIds(linkFileIds);
|
||||
// 添加临时的文件管理的文件
|
||||
taskRequest.getRefFiles().addAll(getApiExecuteFileInfo(fileMetadataList));
|
||||
taskResourceFile.getRefFiles().addAll(getApiExecuteFileInfo(fileMetadataList));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -384,12 +470,11 @@ public class ApiExecuteService {
|
|||
* 处理运行的资源所关联的文件信息
|
||||
*
|
||||
* @param runRequest
|
||||
* @param taskRequest
|
||||
*/
|
||||
private void setTaskRefFileParam(ApiResourceRunRequest runRequest, TaskRequestDTO taskRequest) {
|
||||
private void setTaskRefFileParam(ApiResourceRunRequest runRequest, TaskResourceFile taskResourceFile, String resourceId) {
|
||||
// 查询包括资源所需的文件
|
||||
Set<String> resourceIdsSet = runRequest.getFileResourceIds();
|
||||
resourceIdsSet.add(taskRequest.getResourceId());
|
||||
resourceIdsSet.add(resourceId);
|
||||
List<String> resourceIds = resourceIdsSet.stream().collect(Collectors.toList());
|
||||
SubListUtils.dealForSubList(resourceIds, 50, subResourceIds -> {
|
||||
// 查询通过本地上传的文件
|
||||
|
@ -406,7 +491,7 @@ public class ApiExecuteService {
|
|||
return apiExecuteFileInfo;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
taskRequest.setLocalFiles(localFiles);
|
||||
taskResourceFile.setLocalFiles(localFiles);
|
||||
|
||||
// 查询关联的文件管理的文件
|
||||
List<ApiExecuteFileInfo> refFiles = fileAssociationService.getFiles(subResourceIds).
|
||||
|
@ -421,11 +506,11 @@ public class ApiExecuteService {
|
|||
}
|
||||
return refFileInfo;
|
||||
}).collect(Collectors.toList());
|
||||
taskRequest.setRefFiles(refFiles);
|
||||
taskResourceFile.setRefFiles(refFiles);
|
||||
});
|
||||
}
|
||||
|
||||
private List<ApiExecuteFileInfo> getApiExecuteFileInfo(List<FileMetadata> fileMetadataList) {
|
||||
private CopyOnWriteArrayList<ApiExecuteFileInfo> getApiExecuteFileInfo(List<FileMetadata> fileMetadataList) {
|
||||
return fileMetadataList.stream()
|
||||
.map(file -> {
|
||||
ApiExecuteFileInfo tempFileInfo = getApiExecuteFileInfo(file.getId(), file.getOriginalName(),
|
||||
|
@ -436,7 +521,7 @@ public class ApiExecuteService {
|
|||
tempFileInfo.setFileModuleRepositoryDTO(fileManagementService.getFileModuleRepositoryDTO(file.getModuleId()));
|
||||
}
|
||||
return tempFileInfo;
|
||||
}).toList();
|
||||
}).collect(Collectors.toCollection(CopyOnWriteArrayList::new));
|
||||
}
|
||||
|
||||
private ApiExecuteFileInfo getApiExecuteFileInfo(String fileId, String fileName, String projectId) {
|
||||
|
@ -459,7 +544,7 @@ public class ApiExecuteService {
|
|||
* @param config 参数配置
|
||||
* @return 执行脚本
|
||||
*/
|
||||
private String parseExecuteScript(AbstractMsTestElement msTestElement, ParameterConfig config) {
|
||||
public String parseExecuteScript(AbstractMsTestElement msTestElement, ParameterConfig config) {
|
||||
// 解析生成脚本
|
||||
TestElementParser defaultParser = TestElementParserFactory.getDefaultParser();
|
||||
return defaultParser.parse(msTestElement, config);
|
||||
|
@ -510,7 +595,7 @@ public class ApiExecuteService {
|
|||
}
|
||||
|
||||
public void downloadFile(String reportId, String testId, FileRequest fileRequest, HttpServletResponse response) throws Exception {
|
||||
String key = getScriptRedisKey(reportId, testId);
|
||||
String key = getTaskKey(reportId, testId);
|
||||
if (BooleanUtils.isTrue(stringRedisTemplate.hasKey(key))) {
|
||||
FileRepository repository = StringUtils.isBlank(fileRequest.getStorage()) ? FileCenter.getDefaultRepository()
|
||||
: FileCenter.getRepository(fileRequest.getStorage());
|
||||
|
@ -546,14 +631,17 @@ public class ApiExecuteService {
|
|||
*/
|
||||
public TaskRequestDTO apiExecute(ApiResourceRunRequest runRequest, TaskRequestDTO taskRequest, ApiParamConfig apiParamConfig) {
|
||||
// 设置使用脚本前后置的公共脚本信息
|
||||
AbstractMsTestElement testElement = runRequest.getTestElement();
|
||||
apiCommonService.setEnableCommonScriptProcessorInfo(testElement);
|
||||
testElement.setResourceId(taskRequest.getResourceId());
|
||||
testElement.setStepId(taskRequest.getResourceId());
|
||||
testElement.setProjectId(taskRequest.getProjectId());
|
||||
setTestElementParam(runRequest.getTestElement(), taskRequest.getTaskInfo().getProjectId(), taskRequest.getTaskItem());
|
||||
return execute(runRequest, taskRequest, apiParamConfig);
|
||||
}
|
||||
|
||||
public void setTestElementParam(AbstractMsTestElement testElement, String projectId, TaskItem taskItem) {
|
||||
apiCommonService.setEnableCommonScriptProcessorInfo(testElement);
|
||||
testElement.setResourceId(taskItem.getResourceId());
|
||||
testElement.setStepId(taskItem.getResourceId());
|
||||
testElement.setProjectId(projectId);
|
||||
}
|
||||
|
||||
public ApiParamConfig getApiParamConfig(String reportId) {
|
||||
ApiParamConfig paramConfig = new ApiParamConfig();
|
||||
paramConfig.setTestElementClassPluginIdMap(apiPluginService.getTestElementPluginMap());
|
||||
|
@ -562,14 +650,37 @@ public class ApiExecuteService {
|
|||
return paramConfig;
|
||||
}
|
||||
|
||||
public ApiParamConfig getApiParamConfig(String reportId, String projectId) {
|
||||
ApiParamConfig paramConfig = new ApiParamConfig();
|
||||
paramConfig.setTestElementClassPluginIdMap(apiPluginService.getTestElementPluginMap());
|
||||
paramConfig.setTestElementClassProtocolMap(apiPluginService.getTestElementProtocolMap());
|
||||
paramConfig.setReportId(reportId);
|
||||
paramConfig.setGlobalParams(getGlobalParam(projectId));
|
||||
return paramConfig;
|
||||
}
|
||||
|
||||
public TaskRequestDTO getTaskRequest(String reportId, String resourceId, String projectId) {
|
||||
TaskRequestDTO taskRequest = new TaskRequestDTO();
|
||||
taskRequest.setReportId(reportId);
|
||||
taskRequest.setResourceId(resourceId);
|
||||
taskRequest.setProjectId(projectId);
|
||||
TaskInfo taskInfo = getTaskInfo(projectId);
|
||||
TaskItem taskItem = getTaskItem(reportId, resourceId);
|
||||
taskRequest.setTaskInfo(taskInfo);
|
||||
taskRequest.setTaskItem(taskItem);
|
||||
return taskRequest;
|
||||
}
|
||||
|
||||
public TaskInfo getTaskInfo(String projectId) {
|
||||
TaskInfo taskInfo = new TaskInfo();
|
||||
taskInfo.setProjectId(projectId);
|
||||
return taskInfo;
|
||||
}
|
||||
|
||||
public TaskItem getTaskItem(String reportId, String resourceId) {
|
||||
TaskItem taskItem = new TaskItem();
|
||||
taskItem.setReportId(reportId);
|
||||
taskItem.setResourceId(resourceId);
|
||||
return taskItem;
|
||||
}
|
||||
|
||||
public String getDebugRunModule(boolean isFrontendDebug) {
|
||||
return isFrontendDebug ? ApiExecuteRunMode.FRONTEND_DEBUG.name() : ApiExecuteRunMode.BACKEND_DEBUG.name();
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@ import io.metersphere.project.mapper.ProjectMapper;
|
|||
import io.metersphere.sdk.constants.*;
|
||||
import io.metersphere.sdk.dto.api.result.ProcessResultDTO;
|
||||
import io.metersphere.sdk.dto.api.result.TaskResultDTO;
|
||||
import io.metersphere.sdk.dto.api.task.TaskInfo;
|
||||
import io.metersphere.sdk.dto.api.task.TaskItem;
|
||||
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
|
||||
import io.metersphere.sdk.exception.MSException;
|
||||
import io.metersphere.sdk.util.*;
|
||||
|
@ -293,11 +295,14 @@ public class ApiTaskCenterService {
|
|||
LogUtils.error(e);
|
||||
} finally {
|
||||
subList.forEach(reportId -> {
|
||||
taskRequestDTO.setReportId(reportId);
|
||||
taskRequestDTO.setResourceType(request.getModuleType());
|
||||
taskRequestDTO.getRunModeConfig().setIntegratedReport(integrationMap.get(reportId));
|
||||
TaskInfo taskInfo = taskRequestDTO.getTaskInfo();
|
||||
TaskItem taskItem = new TaskItem();
|
||||
taskRequestDTO.setTaskItem(taskItem);
|
||||
taskItem.setReportId(reportId);
|
||||
taskInfo.setResourceType(request.getModuleType());
|
||||
taskInfo.getRunModeConfig().setIntegratedReport(integrationMap.get(reportId));
|
||||
if (BooleanUtils.isTrue(integrationMap.get(reportId))) {
|
||||
taskRequestDTO.getRunModeConfig().getCollectionReport().setReportId(reportId);
|
||||
taskInfo.getRunModeConfig().getCollectionReport().setReportId(reportId);
|
||||
}
|
||||
result.setRequest(taskRequestDTO);
|
||||
kafkaTemplate.send(KafkaTopicConstants.API_REPORT_TOPIC, JSON.toJSONString(result));
|
||||
|
|
|
@ -25,6 +25,7 @@ import io.metersphere.project.service.MoveNodeService;
|
|||
import io.metersphere.project.service.ProjectService;
|
||||
import io.metersphere.sdk.constants.ApiFileResourceType;
|
||||
import io.metersphere.sdk.constants.DefaultRepositoryDir;
|
||||
import io.metersphere.sdk.dto.api.task.TaskInfo;
|
||||
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
|
||||
import io.metersphere.sdk.exception.MSException;
|
||||
import io.metersphere.sdk.util.BeanUtils;
|
||||
|
@ -213,10 +214,11 @@ public class ApiDebugService extends MoveNodeService {
|
|||
ApiParamConfig apiParamConfig = apiExecuteService.getApiParamConfig(request.getReportId());
|
||||
|
||||
TaskRequestDTO taskRequest = apiExecuteService.getTaskRequest(request.getReportId(), request.getId(), request.getProjectId());
|
||||
taskRequest.setSaveResult(false);
|
||||
taskRequest.setRealTime(true);
|
||||
taskRequest.setResourceType(ApiResourceType.API_DEBUG.name());
|
||||
taskRequest.setRunMode(apiExecuteService.getDebugRunModule(request.getFrontendDebug()));
|
||||
TaskInfo taskInfo = taskRequest.getTaskInfo();
|
||||
taskInfo.setSaveResult(false);
|
||||
taskInfo.setRealTime(true);
|
||||
taskInfo.setResourceType(ApiResourceType.API_DEBUG.name());
|
||||
taskInfo.setRunMode(apiExecuteService.getDebugRunModule(request.getFrontendDebug()));
|
||||
return apiExecuteService.apiExecute(runRequest, taskRequest, apiParamConfig);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ import io.metersphere.sdk.constants.ApplicationNumScope;
|
|||
import io.metersphere.sdk.constants.DefaultRepositoryDir;
|
||||
import io.metersphere.sdk.constants.ModuleConstants;
|
||||
import io.metersphere.sdk.domain.OperationLogBlob;
|
||||
import io.metersphere.sdk.dto.api.task.TaskInfo;
|
||||
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
|
||||
import io.metersphere.sdk.exception.MSException;
|
||||
import io.metersphere.sdk.mapper.OperationLogBlobMapper;
|
||||
|
@ -1145,13 +1146,14 @@ public class ApiDefinitionService extends MoveNodeService {
|
|||
public TaskRequestDTO debug(ApiDefinitionRunRequest request) {
|
||||
ApiResourceRunRequest runRequest = apiExecuteService.getApiResourceRunRequest(request);
|
||||
EnvironmentInfoDTO environmentInfoDTO = environmentService.get(request.getEnvironmentId());
|
||||
ApiParamConfig apiParamConfig = apiExecuteService.getApiParamConfig(request.getReportId());
|
||||
ApiParamConfig apiParamConfig = apiExecuteService.getApiParamConfig(request.getReportId(), request.getProjectId());
|
||||
|
||||
TaskRequestDTO taskRequest = apiExecuteService.getTaskRequest(request.getReportId(), request.getId(), request.getProjectId());
|
||||
taskRequest.setSaveResult(false);
|
||||
taskRequest.setRealTime(true);
|
||||
taskRequest.setResourceType(ApiResourceType.API.name());
|
||||
taskRequest.setRunMode(apiExecuteService.getDebugRunModule(request.getFrontendDebug()));
|
||||
TaskInfo taskInfo = taskRequest.getTaskInfo();
|
||||
taskInfo.setSaveResult(false);
|
||||
taskInfo.setRealTime(true);
|
||||
taskInfo.setResourceType(ApiResourceType.API.name());
|
||||
taskInfo.setRunMode(apiExecuteService.getDebugRunModule(request.getFrontendDebug()));
|
||||
|
||||
AbstractMsTestElement msTestElement = runRequest.getTestElement();
|
||||
|
||||
|
|
|
@ -1,23 +1,14 @@
|
|||
package io.metersphere.api.service.definition;
|
||||
|
||||
import io.metersphere.api.domain.*;
|
||||
import io.metersphere.api.dto.ApiDefinitionExecuteInfo;
|
||||
import io.metersphere.api.dto.ApiParamConfig;
|
||||
import io.metersphere.api.dto.debug.ApiResourceRunRequest;
|
||||
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.api.utils.ApiDataUtils;
|
||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||
import io.metersphere.project.service.EnvironmentService;
|
||||
import io.metersphere.sdk.constants.*;
|
||||
import io.metersphere.sdk.dto.api.task.ApiRunModeConfigDTO;
|
||||
import io.metersphere.sdk.dto.api.task.CollectionReportDTO;
|
||||
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
|
||||
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;
|
||||
|
@ -34,7 +25,6 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -47,14 +37,10 @@ public class ApiTestCaseBatchRunService {
|
|||
@Resource
|
||||
private ExtApiTestCaseMapper extApiTestCaseMapper;
|
||||
@Resource
|
||||
private ApiTestCaseBlobMapper apiTestCaseBlobMapper;
|
||||
@Resource
|
||||
private ApiTestCaseService apiTestCaseService;
|
||||
@Resource
|
||||
private ApiExecuteService apiExecuteService;
|
||||
@Resource
|
||||
private EnvironmentService environmentService;
|
||||
@Resource
|
||||
private ApiExecutionQueueService apiExecutionQueueService;
|
||||
@Resource
|
||||
private ApiExecutionSetService apiExecutionSetService;
|
||||
|
@ -63,10 +49,6 @@ public class ApiTestCaseBatchRunService {
|
|||
@Resource
|
||||
private ApiBatchRunBaseService apiBatchRunBaseService;
|
||||
@Resource
|
||||
private ApiCommonService apiCommonService;
|
||||
@Resource
|
||||
private ApiDefinitionMapper apiDefinitionMapper;
|
||||
@Resource
|
||||
private ApiReportMapper apiReportMapper;
|
||||
@Resource
|
||||
private ApiReportDetailMapper apiReportDetailMapper;
|
||||
|
@ -168,49 +150,32 @@ public class ApiTestCaseBatchRunService {
|
|||
|
||||
// 集成报告,执行前先设置成 RUNNING
|
||||
setRunningIntegrateReport(runModeConfig);
|
||||
List<TaskItem> taskItems = new ArrayList<>(ids.size());
|
||||
|
||||
// 分批查询
|
||||
SubListUtils.dealForSubList(ids, 100, subIds -> {
|
||||
// 这里ID顺序和队列的ID顺序保持一致
|
||||
for (String id : ids) {
|
||||
ApiTestCase apiTestCase = apiCaseMap.get(id);
|
||||
|
||||
AtomicInteger errorCount = new AtomicInteger();
|
||||
Map<String, ApiTestCaseBlob> apiTestCaseBlobMap = apiTestCaseService.getBlobByIds(subIds).stream()
|
||||
.collect(Collectors.toMap(ApiTestCaseBlob::getId, Function.identity()));
|
||||
|
||||
// 获取用例和定义信息的map,key 为用例ID,value 为接口定义信息
|
||||
Map<String, ApiDefinitionExecuteInfo> definitionExecuteInfoMap = apiTestCaseService.getModuleInfoByIds(subIds).stream()
|
||||
.collect(Collectors.toMap(ApiDefinitionExecuteInfo::getResourceId, Function.identity()));
|
||||
|
||||
// 这里ID顺序和队列的ID顺序保持一致
|
||||
for (String id : subIds) {
|
||||
String reportId = null;
|
||||
try {
|
||||
ApiTestCase apiTestCase = apiCaseMap.get(id);
|
||||
ApiTestCaseBlob apiTestCaseBlob = apiTestCaseBlobMap.get(id);
|
||||
|
||||
if (apiTestCase == null) {
|
||||
if (runModeConfig.isIntegratedReport()) {
|
||||
// 用例不存在,则在执行集合中删除
|
||||
apiExecutionSetService.removeItem(runModeConfig.getCollectionReport().getReportId(), id);
|
||||
}
|
||||
LogUtils.info("当前执行任务的用例已删除 {}", id);
|
||||
break;
|
||||
}
|
||||
|
||||
// 如果是集成报告则生成唯一的虚拟ID,非集成报告使用单用例的报告ID
|
||||
reportId = runModeConfig.isIntegratedReport() ? UUID.randomUUID().toString() : caseReportMap.get(id);
|
||||
TaskRequestDTO taskRequest = getTaskRequestDTO(reportId, apiTestCase, runModeConfig);
|
||||
taskRequest.setRequestCount(1L);
|
||||
execute(taskRequest, apiTestCase, apiTestCaseBlob, definitionExecuteInfoMap.get(apiTestCase.getId()));
|
||||
} catch (Exception e) {
|
||||
LogUtils.error("执行用例失败 {}-{}", reportId, id);
|
||||
LogUtils.error(e);
|
||||
if (errorCount.getAndIncrement() > 10) {
|
||||
LogUtils.error("批量执行用例失败,错误次数超过10次,停止执行");
|
||||
return;
|
||||
}
|
||||
if (apiTestCase == null) {
|
||||
if (runModeConfig.isIntegratedReport()) {
|
||||
// 用例不存在,则在执行集合中删除
|
||||
apiExecutionSetService.removeItem(runModeConfig.getCollectionReport().getReportId(), id);
|
||||
}
|
||||
LogUtils.info("当前执行任务的用例已删除 {}", id);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// 如果是集成报告则生成唯一的虚拟ID,非集成报告使用单用例的报告ID
|
||||
String reportId = runModeConfig.isIntegratedReport() ? UUID.randomUUID().toString() : caseReportMap.get(id);
|
||||
|
||||
TaskItem taskItem = apiExecuteService.getTaskItem(reportId, id);
|
||||
taskItem.setRequestCount(1L);
|
||||
taskItems.add(taskItem);
|
||||
}
|
||||
|
||||
TaskBatchRequestDTO taskRequest = getTaskBatchRequestDTO(request.getProjectId(), runModeConfig);
|
||||
taskRequest.setTaskItems(taskItems);
|
||||
apiExecuteService.batchExecute(taskRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -309,7 +274,6 @@ public class ApiTestCaseBatchRunService {
|
|||
String resourceId = queueDetail.getResourceId();
|
||||
|
||||
ApiTestCase apiTestCase = apiTestCaseMapper.selectByPrimaryKey(resourceId);
|
||||
ApiTestCaseBlob apiTestCaseBlob = apiTestCaseBlobMapper.selectByPrimaryKey(resourceId);
|
||||
|
||||
String reportId;
|
||||
if (runModeConfig.isIntegratedReport()) {
|
||||
|
@ -323,41 +287,39 @@ public class ApiTestCaseBatchRunService {
|
|||
LogUtils.info("当前执行任务的用例已删除 {}", resourceId);
|
||||
return;
|
||||
}
|
||||
ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey(apiTestCase.getApiDefinitionId());
|
||||
|
||||
TaskRequestDTO taskRequest = getTaskRequestDTO(reportId, apiTestCase, runModeConfig);
|
||||
taskRequest.setQueueId(queue.getQueueId());
|
||||
taskRequest.setRequestCount(1L);
|
||||
execute(taskRequest, apiTestCase, apiTestCaseBlob, BeanUtils.copyBean(new ApiDefinitionExecuteInfo(), apiDefinition));
|
||||
}
|
||||
taskRequest.getTaskInfo().setQueueId(queue.getQueueId());
|
||||
taskRequest.getTaskItem().setRequestCount(1L);
|
||||
|
||||
/**
|
||||
* 执行批量的单个任务
|
||||
*
|
||||
* @param apiTestCase
|
||||
* @param apiTestCaseBlob
|
||||
*/
|
||||
public void execute(TaskRequestDTO taskRequest, ApiTestCase apiTestCase, ApiTestCaseBlob apiTestCaseBlob, ApiDefinitionExecuteInfo definitionExecuteInfo) {
|
||||
ApiParamConfig apiParamConfig = apiExecuteService.getApiParamConfig(taskRequest.getReportId());
|
||||
ApiResourceRunRequest runRequest = new ApiResourceRunRequest();
|
||||
runRequest.setTestElement(ApiDataUtils.parseObject(new String(apiTestCaseBlob.getRequest()), AbstractMsTestElement.class));
|
||||
|
||||
// 设置环境信息
|
||||
apiParamConfig.setEnvConfig(environmentService.get(getEnvId(taskRequest.getRunModeConfig(), apiTestCase)));
|
||||
// 设置 method 等信息
|
||||
apiCommonService.setApiDefinitionExecuteInfo(runRequest.getTestElement(), definitionExecuteInfo);
|
||||
|
||||
apiExecuteService.apiExecute(runRequest, taskRequest, apiParamConfig);
|
||||
apiExecuteService.execute(taskRequest);
|
||||
}
|
||||
|
||||
private TaskRequestDTO getTaskRequestDTO(String reportId, ApiTestCase apiTestCase, ApiRunModeConfigDTO runModeConfig) {
|
||||
TaskRequestDTO taskRequest = apiTestCaseService.getTaskRequest(reportId, apiTestCase.getId(), apiTestCase.getProjectId(), ApiExecuteRunMode.RUN.name());
|
||||
taskRequest.setSaveResult(true);
|
||||
taskRequest.setRealTime(false);
|
||||
taskRequest.setRunModeConfig(runModeConfig);
|
||||
TaskRequestDTO taskRequest = new TaskRequestDTO();
|
||||
TaskItem taskItem = apiExecuteService.getTaskItem(reportId, apiTestCase.getId());
|
||||
TaskInfo taskInfo = getTaskInfo(apiTestCase.getProjectId(), runModeConfig);
|
||||
taskRequest.setTaskInfo(taskInfo);
|
||||
taskRequest.setTaskItem(taskItem);
|
||||
return taskRequest;
|
||||
}
|
||||
|
||||
private TaskBatchRequestDTO getTaskBatchRequestDTO(String projectId, ApiRunModeConfigDTO runModeConfig) {
|
||||
TaskBatchRequestDTO taskRequest = new TaskBatchRequestDTO();
|
||||
TaskInfo taskInfo = getTaskInfo(projectId, runModeConfig);
|
||||
taskRequest.setTaskInfo(taskInfo);
|
||||
return taskRequest;
|
||||
}
|
||||
|
||||
private TaskInfo getTaskInfo(String projectId, ApiRunModeConfigDTO runModeConfig) {
|
||||
TaskInfo taskInfo = apiTestCaseService.getTaskInfo(projectId, ApiExecuteRunMode.RUN.name());
|
||||
taskInfo.setSaveResult(true);
|
||||
taskInfo.setRealTime(false);
|
||||
taskInfo.setNeedParseScript(true);
|
||||
taskInfo.setRunModeConfig(runModeConfig);
|
||||
return taskInfo;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 预生成用例的执行报告
|
||||
|
@ -387,7 +349,7 @@ public class ApiTestCaseBatchRunService {
|
|||
|
||||
private ApiReport getApiReport(ApiRunModeConfigDTO runModeConfig, ApiTestCase apiTestCase, String userId) {
|
||||
ApiReport apiReport = getApiReport(runModeConfig, userId);
|
||||
apiReport.setEnvironmentId(getEnvId(runModeConfig, apiTestCase));
|
||||
apiReport.setEnvironmentId(apiTestCaseService.getEnvId(runModeConfig, apiTestCase));
|
||||
apiReport.setName(apiTestCase.getName() + "_" + DateUtils.getTimeString(System.currentTimeMillis()));
|
||||
apiReport.setProjectId(apiTestCase.getProjectId());
|
||||
apiReport.setTriggerMode(TaskTriggerMode.BATCH.name());
|
||||
|
@ -403,18 +365,6 @@ public class ApiTestCaseBatchRunService {
|
|||
return apiReport;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取执行的环境ID
|
||||
* 优先使用运行配置的环境
|
||||
* 没有则使用用例自身的环境
|
||||
*
|
||||
* @param runModeConfig
|
||||
* @param apiTestCase
|
||||
* @return
|
||||
*/
|
||||
public String getEnvId(ApiRunModeConfigDTO runModeConfig, ApiTestCase apiTestCase) {
|
||||
return StringUtils.isBlank(runModeConfig.getEnvironmentId()) ? apiTestCase.getEnvironmentId() : runModeConfig.getEnvironmentId();
|
||||
}
|
||||
|
||||
public void updateStopOnFailureApiReport(ExecutionQueue queue) {
|
||||
ApiRunModeConfigDTO runModeConfig = queue.getRunModeConfig();
|
||||
|
|
|
@ -25,7 +25,7 @@ import io.metersphere.project.service.MoveNodeService;
|
|||
import io.metersphere.sdk.constants.*;
|
||||
import io.metersphere.sdk.domain.Environment;
|
||||
import io.metersphere.sdk.domain.EnvironmentExample;
|
||||
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
|
||||
import io.metersphere.sdk.dto.api.task.*;
|
||||
import io.metersphere.sdk.exception.MSException;
|
||||
import io.metersphere.sdk.mapper.EnvironmentMapper;
|
||||
import io.metersphere.sdk.util.*;
|
||||
|
@ -693,16 +693,18 @@ public class ApiTestCaseService extends MoveNodeService {
|
|||
String poolId = apiExecuteService.getProjectApiResourcePoolId(apiTestCase.getProjectId());
|
||||
|
||||
TaskRequestDTO taskRequest = getTaskRequest(reportId, apiTestCase.getId(), apiTestCase.getProjectId(), ApiExecuteRunMode.RUN.name());
|
||||
taskRequest.getRunModeConfig().setPoolId(poolId);
|
||||
taskRequest.setSaveResult(true);
|
||||
TaskItem taskItem = taskRequest.getTaskItem();
|
||||
TaskInfo taskInfo = taskRequest.getTaskInfo();
|
||||
taskInfo.getRunModeConfig().setPoolId(poolId);
|
||||
taskInfo.setSaveResult(true);
|
||||
|
||||
if (StringUtils.isEmpty(taskRequest.getReportId())) {
|
||||
taskRequest.setRealTime(false);
|
||||
if (StringUtils.isEmpty(taskItem.getReportId())) {
|
||||
taskInfo.setRealTime(false);
|
||||
reportId = IDGenerator.nextStr();
|
||||
taskRequest.setReportId(reportId);
|
||||
taskItem.setReportId(reportId);
|
||||
} else {
|
||||
// 如果传了报告ID,则实时获取结果
|
||||
taskRequest.setRealTime(true);
|
||||
taskInfo.setRealTime(true);
|
||||
}
|
||||
|
||||
// 初始化报告
|
||||
|
@ -721,8 +723,8 @@ public class ApiTestCaseService extends MoveNodeService {
|
|||
public TaskRequestDTO debug(ApiCaseRunRequest request) {
|
||||
TaskRequestDTO taskRequest = getTaskRequest(request.getReportId(), request.getId(),
|
||||
request.getProjectId(), apiExecuteService.getDebugRunModule(request.getFrontendDebug()));
|
||||
taskRequest.setSaveResult(false);
|
||||
taskRequest.setRealTime(true);
|
||||
taskRequest.getTaskInfo().setSaveResult(false);
|
||||
taskRequest.getTaskInfo().setRealTime(true);
|
||||
|
||||
ApiResourceRunRequest runRequest = apiExecuteService.getApiResourceRunRequest(request);
|
||||
|
||||
|
@ -731,7 +733,7 @@ public class ApiTestCaseService extends MoveNodeService {
|
|||
|
||||
private TaskRequestDTO doExecute(TaskRequestDTO taskRequest, ApiResourceRunRequest runRequest, String apiDefinitionId, String envId) {
|
||||
|
||||
ApiParamConfig apiParamConfig = apiExecuteService.getApiParamConfig(taskRequest.getReportId());
|
||||
ApiParamConfig apiParamConfig = apiExecuteService.getApiParamConfig(taskRequest.getTaskItem().getReportId(), taskRequest.getTaskInfo().getProjectId());
|
||||
|
||||
ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey(apiDefinitionId);
|
||||
|
||||
|
@ -743,6 +745,49 @@ public class ApiTestCaseService extends MoveNodeService {
|
|||
return apiExecuteService.apiExecute(runRequest, taskRequest, apiParamConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取执行脚本
|
||||
*/
|
||||
public GetRunScriptResult getRunScript(GetRunScriptRequest request) {
|
||||
TaskItem taskItem = request.getTaskItem();
|
||||
ApiTestCase apiTestCase = apiTestCaseMapper.selectByPrimaryKey(taskItem.getResourceId());
|
||||
ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey(apiTestCase.getApiDefinitionId());
|
||||
ApiTestCaseBlob apiTestCaseBlob = apiTestCaseBlobMapper.selectByPrimaryKey(taskItem.getResourceId());
|
||||
ApiParamConfig apiParamConfig = apiExecuteService.getApiParamConfig(taskItem.getReportId(), apiTestCase.getProjectId());
|
||||
|
||||
AbstractMsTestElement msTestElement = ApiDataUtils.parseObject(new String(apiTestCaseBlob.getRequest()), AbstractMsTestElement.class);
|
||||
// 设置 method 等信息
|
||||
apiCommonService.setApiDefinitionExecuteInfo(msTestElement, BeanUtils.copyBean(new ApiDefinitionExecuteInfo(), apiDefinition));
|
||||
|
||||
apiExecuteService.setTestElementParam(msTestElement, apiTestCase.getProjectId(), request.getTaskItem());
|
||||
|
||||
// 设置环境信息
|
||||
apiParamConfig.setEnvConfig(environmentService.get(getEnvId(request.getRunModeConfig(), apiTestCase)));
|
||||
GetRunScriptResult runScriptResult = new GetRunScriptResult();
|
||||
// 记录请求数量
|
||||
runScriptResult.setRequestCount(1L);
|
||||
runScriptResult.setScript(apiExecuteService.parseExecuteScript(msTestElement, apiParamConfig));
|
||||
|
||||
// 设置资源关联的文件信息
|
||||
apiExecuteService.setTaskItemFileParam(taskItem);
|
||||
runScriptResult.setTaskResourceFile(taskItem.getTaskResourceFile());
|
||||
runScriptResult.setRefProjectResource(taskItem.getRefProjectResource());
|
||||
return runScriptResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取执行的环境ID
|
||||
* 优先使用运行配置的环境
|
||||
* 没有则使用用例自身的环境
|
||||
*
|
||||
* @param runModeConfig
|
||||
* @param apiTestCase
|
||||
* @return
|
||||
*/
|
||||
public String getEnvId(ApiRunModeConfigDTO runModeConfig, ApiTestCase apiTestCase) {
|
||||
return StringUtils.isBlank(runModeConfig.getEnvironmentId()) ? apiTestCase.getEnvironmentId() : runModeConfig.getEnvironmentId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 预生成用例的执行报告
|
||||
*
|
||||
|
@ -802,12 +847,22 @@ public class ApiTestCaseService extends MoveNodeService {
|
|||
}
|
||||
|
||||
public TaskRequestDTO getTaskRequest(String reportId, String resourceId, String projectId, String runModule) {
|
||||
TaskRequestDTO taskRequest = apiExecuteService.getTaskRequest(reportId, resourceId, projectId);
|
||||
taskRequest.setResourceType(ApiResourceType.API_CASE.name());
|
||||
taskRequest.setRunMode(runModule);
|
||||
TaskRequestDTO taskRequest = new TaskRequestDTO();
|
||||
TaskItem taskItem = apiExecuteService.getTaskItem(reportId, resourceId);
|
||||
TaskInfo taskInfo = getTaskInfo(projectId, runModule);
|
||||
taskRequest.setTaskInfo(taskInfo);
|
||||
taskRequest.setTaskItem(taskItem);
|
||||
return taskRequest;
|
||||
}
|
||||
|
||||
public TaskInfo getTaskInfo(String projectId, String runModule) {
|
||||
TaskInfo taskInfo = apiExecuteService.getTaskInfo(projectId);
|
||||
taskInfo.setResourceType(ApiResourceType.API_CASE.name());
|
||||
taskInfo.setRunMode(runModule);
|
||||
taskInfo.setNeedParseScript(false);
|
||||
return taskInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePos(String id, long pos) {
|
||||
extApiTestCaseMapper.updatePos(id, pos);
|
||||
|
|
|
@ -23,12 +23,16 @@ public class ApiExecutionSetService {
|
|||
*/
|
||||
public void initSet(String setId, List<String> resourceIds) {
|
||||
resourceIds.forEach(resourceId -> {
|
||||
String key = SET_PREFIX + setId;
|
||||
String key = getKey(setId);
|
||||
redisTemplate.opsForSet().add(key, resourceId);
|
||||
redisTemplate.expire(key, 1, TimeUnit.DAYS);
|
||||
});
|
||||
}
|
||||
|
||||
private String getKey(String setId) {
|
||||
return SET_PREFIX + setId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从执行集合中去除选项
|
||||
*/
|
||||
|
|
|
@ -4,39 +4,27 @@ import io.metersphere.api.domain.ApiScenario;
|
|||
import io.metersphere.api.domain.ApiScenarioRecord;
|
||||
import io.metersphere.api.domain.ApiScenarioReport;
|
||||
import io.metersphere.api.domain.ApiScenarioReportStep;
|
||||
import io.metersphere.api.dto.ApiScenarioParamConfig;
|
||||
import io.metersphere.api.dto.ApiScenarioParseTmpParam;
|
||||
import io.metersphere.api.dto.debug.ApiResourceRunRequest;
|
||||
import io.metersphere.api.dto.request.MsScenario;
|
||||
import io.metersphere.api.dto.scenario.ApiScenarioBatchRunRequest;
|
||||
import io.metersphere.api.dto.scenario.ApiScenarioDetail;
|
||||
import io.metersphere.api.dto.scenario.ApiScenarioParseParam;
|
||||
import io.metersphere.api.dto.scenario.ApiScenarioStepDTO;
|
||||
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.ApiExecuteService;
|
||||
import io.metersphere.api.service.queue.ApiExecutionQueueService;
|
||||
import io.metersphere.api.service.queue.ApiExecutionSetService;
|
||||
import io.metersphere.api.utils.ExecTask;
|
||||
import io.metersphere.api.utils.TaskRunnerUtils;
|
||||
import io.metersphere.sdk.constants.*;
|
||||
import io.metersphere.sdk.dto.api.task.ApiRunModeConfigDTO;
|
||||
import io.metersphere.sdk.dto.api.task.CollectionReportDTO;
|
||||
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
|
||||
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.system.dto.pool.TestResourcePoolReturnDTO;
|
||||
import io.metersphere.system.uid.IDGenerator;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
|
@ -45,7 +33,6 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -68,9 +55,10 @@ public class ApiScenarioBatchRunService {
|
|||
private ApiBatchRunBaseService apiBatchRunBaseService;
|
||||
@Resource
|
||||
private ExtApiScenarioMapper extApiScenarioMapper;
|
||||
|
||||
@Value("${spring.datasource.hikari.maximum-pool-size}")
|
||||
private int maximumPoolSize;
|
||||
@Resource
|
||||
private ApiScenarioMapper apiScenarioMapper;
|
||||
@Resource
|
||||
private ApiScenarioRunService apiScenarioRunService;
|
||||
|
||||
/**
|
||||
* 异步批量执行
|
||||
|
@ -148,31 +136,17 @@ public class ApiScenarioBatchRunService {
|
|||
// 集成报告,执行前先设置成 RUNNING
|
||||
setRunningIntegrateReport(runModeConfig);
|
||||
|
||||
TestResourcePoolReturnDTO testResourcePoolDTO = apiExecuteService.getGetResourcePoolNodeDTO(runModeConfig, request.getProjectId());
|
||||
List<ApiScenarioDetail> apiScenarioDetails = apiScenarioService.getForRuns(ids);
|
||||
List<TaskItem> taskItems = ids.stream()
|
||||
.map(id -> {
|
||||
String reportId = runModeConfig.isIntegratedReport() ? IDGenerator.nextStr() : scenarioReportMap.get(id);
|
||||
return apiExecuteService.getTaskItem(reportId, id);
|
||||
}).toList();
|
||||
TaskBatchRequestDTO taskRequest = getTaskBatchRequestDTO(request.getProjectId(), runModeConfig);
|
||||
taskRequest.setTaskItems(taskItems);
|
||||
|
||||
if (StringUtils.isNotBlank(testResourcePoolDTO.getServerUrl())) {
|
||||
// 独立部署执行专属服务,线程池执行
|
||||
TaskRunnerUtils.setThreadPoolSize(maximumPoolSize / 2 - 10);
|
||||
apiScenarioDetails.forEach(apiScenarioDetail -> {
|
||||
ExecTask execTask = new ExecTask(this, apiScenarioDetail, scenarioReportMap, runModeConfig);
|
||||
TaskRunnerUtils.executeThreadPool(execTask);
|
||||
});
|
||||
} else {
|
||||
// 未独立部署执行专属引用则使用默认循环分发任务
|
||||
apiScenarioDetails.forEach(apiScenarioDetail -> execute(apiScenarioDetail, scenarioReportMap, runModeConfig));
|
||||
}
|
||||
apiExecuteService.batchExecute(taskRequest);
|
||||
}
|
||||
|
||||
public void execute(ApiScenarioDetail apiScenarioDetail, Map<String, String> scenarioReportMap, ApiRunModeConfigDTO runModeConfig) {
|
||||
try {
|
||||
String reportId = runModeConfig.isIntegratedReport() ? IDGenerator.nextStr() : scenarioReportMap.get(apiScenarioDetail.getId());
|
||||
TaskRequestDTO taskRequest = getTaskRequestDTO(reportId, apiScenarioDetail, runModeConfig);
|
||||
execute(taskRequest, apiScenarioDetail);
|
||||
} catch (Exception e) {
|
||||
LogUtils.error("执行用例失败 {}", apiScenarioDetail.getId(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, String> initReport(List<String> ids, ApiRunModeConfigDTO runModeConfig, String userId) {
|
||||
Map<String, String> scenarioReportMap = new HashMap<>();
|
||||
|
@ -214,17 +188,6 @@ public class ApiScenarioBatchRunService {
|
|||
}
|
||||
|
||||
|
||||
private Long getRequestCount(List<ApiScenarioStepDTO> steps) {
|
||||
AtomicLong requestCount = new AtomicLong();
|
||||
apiScenarioService.traversalStepTree(steps, step -> {
|
||||
if (BooleanUtils.isTrue(step.getEnable()) && apiScenarioService.isRequestStep(step)) {
|
||||
requestCount.getAndIncrement();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return requestCount.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 集成报告,执行前先设置成 RUNNING
|
||||
*
|
||||
|
@ -288,81 +251,53 @@ public class ApiScenarioBatchRunService {
|
|||
*/
|
||||
public void executeNextTask(ExecutionQueue queue, ExecutionQueueDetail queueDetail) {
|
||||
ApiRunModeConfigDTO runModeConfig = queue.getRunModeConfig();
|
||||
ApiScenarioDetail apiScenarioDetail = apiScenarioService.getForRun(queueDetail.getResourceId());
|
||||
ApiScenario apiScenario = apiScenarioMapper.selectByPrimaryKey(queueDetail.getResourceId());
|
||||
|
||||
ApiScenarioDetail apiScenarioDetail = apiScenarioRunService.getForRun(queueDetail.getResourceId());
|
||||
if (apiScenarioDetail == null) {
|
||||
LogUtils.info("当前执行任务的用例已删除 {}", queueDetail.getResourceId());
|
||||
return;
|
||||
}
|
||||
|
||||
String reportId;
|
||||
if (runModeConfig.isIntegratedReport()) {
|
||||
reportId = IDGenerator.nextStr();
|
||||
} else {
|
||||
// 独立报告,执行到当前任务时初始化报告
|
||||
reportId = initScenarioReport(runModeConfig, apiScenarioDetail, queue.getUserId()).getApiScenarioReportId();
|
||||
reportId = initScenarioReport(runModeConfig, apiScenario, queue.getUserId()).getApiScenarioReportId();
|
||||
}
|
||||
|
||||
TaskRequestDTO taskRequest = getTaskRequestDTO(reportId, apiScenarioDetail, queue.getRunModeConfig());
|
||||
taskRequest.setQueueId(queue.getQueueId());
|
||||
execute(taskRequest, apiScenarioDetail);
|
||||
TaskRequestDTO taskRequest = getTaskRequestDTO(apiScenario.getProjectId(), queue.getRunModeConfig());
|
||||
TaskItem taskItem = apiExecuteService.getTaskItem(reportId, queueDetail.getResourceId());
|
||||
taskRequest.setTaskItem(taskItem);
|
||||
taskRequest.getTaskInfo().setQueueId(queue.getQueueId());
|
||||
|
||||
apiExecuteService.execute(taskRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行批量的单个任务
|
||||
*/
|
||||
public void execute(TaskRequestDTO taskRequest, ApiScenarioDetail apiScenarioDetail) {
|
||||
ApiRunModeConfigDTO runModeConfig = taskRequest.getRunModeConfig();
|
||||
String reportId = taskRequest.getReportId();
|
||||
String envId = getEnvId(runModeConfig, apiScenarioDetail);
|
||||
boolean envGroup = getEnvGroup(runModeConfig, apiScenarioDetail);
|
||||
|
||||
// 解析生成待执行的场景树
|
||||
MsScenario msScenario = apiScenarioService.getMsScenario(apiScenarioDetail);
|
||||
|
||||
ApiScenarioParseParam parseParam = apiScenarioService.getApiScenarioParseParam(apiScenarioDetail);
|
||||
parseParam.setEnvironmentId(envId);
|
||||
parseParam.setGrouped(envGroup);
|
||||
|
||||
// 初始化报告步骤
|
||||
if (runModeConfig.isIntegratedReport()) {
|
||||
apiScenarioService.initScenarioReportSteps(apiScenarioDetail.getId(), apiScenarioDetail.getSteps(), runModeConfig.getCollectionReport().getReportId());
|
||||
} else {
|
||||
updateReportWaitTime(reportId, parseParam);
|
||||
apiScenarioService.initScenarioReportSteps(apiScenarioDetail.getSteps(), reportId);
|
||||
}
|
||||
|
||||
taskRequest.setReportId(reportId);
|
||||
// 记录请求数量
|
||||
taskRequest.setRequestCount(getRequestCount(apiScenarioDetail.getSteps()));
|
||||
|
||||
msScenario.setResourceId(apiScenarioDetail.getId());
|
||||
ApiScenarioParseTmpParam tmpParam = apiScenarioService.parse(msScenario, apiScenarioDetail.getSteps(), parseParam);
|
||||
|
||||
ApiResourceRunRequest runRequest = apiScenarioService.getApiResourceRunRequest(msScenario, tmpParam);
|
||||
|
||||
ApiScenarioParamConfig parseConfig = apiScenarioService.getApiScenarioParamConfig(parseParam, tmpParam.getScenarioParseEnvInfo());
|
||||
parseConfig.setReportId(reportId);
|
||||
|
||||
apiExecuteService.execute(runRequest, taskRequest, parseConfig);
|
||||
}
|
||||
|
||||
private void updateReportWaitTime(String reportId, ApiScenarioParseParam parseParam) {
|
||||
Long globalWaitTime = apiScenarioService.getGlobalWaitTime(parseParam.getScenarioConfig());
|
||||
if (globalWaitTime != null) {
|
||||
ApiScenarioReport apiScenarioReport = new ApiScenarioReport();
|
||||
apiScenarioReport.setId(reportId);
|
||||
apiScenarioReport.setWaitingTime(globalWaitTime);
|
||||
apiScenarioReportMapper.updateByPrimaryKeySelective(apiScenarioReport);
|
||||
}
|
||||
}
|
||||
|
||||
private TaskRequestDTO getTaskRequestDTO(String reportId, ApiScenarioDetail apiScenarioDetail, ApiRunModeConfigDTO runModeConfig) {
|
||||
TaskRequestDTO taskRequest = apiScenarioService.getTaskRequest(reportId, apiScenarioDetail.getId(), apiScenarioDetail.getProjectId(), ApiExecuteRunMode.RUN.name());
|
||||
taskRequest.setSaveResult(true);
|
||||
taskRequest.setRealTime(false);
|
||||
taskRequest.setRunModeConfig(runModeConfig);
|
||||
private TaskRequestDTO getTaskRequestDTO(String projectId, ApiRunModeConfigDTO runModeConfig) {
|
||||
TaskRequestDTO taskRequest = new TaskRequestDTO();
|
||||
TaskInfo taskInfo = getTaskInfo(projectId, runModeConfig);
|
||||
taskRequest.setTaskInfo(taskInfo);
|
||||
return taskRequest;
|
||||
}
|
||||
|
||||
private TaskBatchRequestDTO getTaskBatchRequestDTO(String projectId, ApiRunModeConfigDTO runModeConfig) {
|
||||
TaskBatchRequestDTO taskRequest = new TaskBatchRequestDTO();
|
||||
TaskInfo taskInfo = getTaskInfo(projectId, runModeConfig);
|
||||
taskRequest.setTaskInfo(taskInfo);
|
||||
return taskRequest;
|
||||
}
|
||||
|
||||
private TaskInfo getTaskInfo(String projectId, ApiRunModeConfigDTO runModeConfig) {
|
||||
TaskInfo taskInfo = apiScenarioRunService.getTaskInfo(projectId, ApiExecuteRunMode.RUN.name());
|
||||
taskInfo.setSaveResult(true);
|
||||
taskInfo.setRealTime(false);
|
||||
taskInfo.setNeedParseScript(true);
|
||||
taskInfo.setRunModeConfig(runModeConfig);
|
||||
return taskInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 预生成用例的执行报告
|
||||
*
|
||||
|
@ -375,7 +310,7 @@ public class ApiScenarioBatchRunService {
|
|||
ApiScenarioReport apiScenarioReport = getScenarioReport(runModeConfig, apiScenario, userId);
|
||||
apiScenarioReport.setId(IDGenerator.nextStr());
|
||||
// 创建报告和用例的关联关系
|
||||
ApiScenarioRecord apiScenarioRecord = apiScenarioService.getApiScenarioRecord(apiScenario, apiScenarioReport);
|
||||
ApiScenarioRecord apiScenarioRecord = apiScenarioRunService.getApiScenarioRecord(apiScenario, apiScenarioReport);
|
||||
apiScenarioReportService.insertApiScenarioReport(List.of(apiScenarioReport), List.of(apiScenarioRecord));
|
||||
return apiScenarioRecord;
|
||||
}
|
||||
|
@ -383,7 +318,7 @@ public class ApiScenarioBatchRunService {
|
|||
|
||||
private ApiScenarioReport getScenarioReport(ApiRunModeConfigDTO runModeConfig, ApiScenario apiScenario, String userId) {
|
||||
ApiScenarioReport apiScenarioReport = getScenarioReport(runModeConfig, userId);
|
||||
apiScenarioReport.setEnvironmentId(getEnvId(runModeConfig, apiScenario));
|
||||
apiScenarioReport.setEnvironmentId(apiScenarioRunService.getEnvId(runModeConfig, apiScenario));
|
||||
apiScenarioReport.setName(apiScenario.getName() + "_" + DateUtils.getTimeString(System.currentTimeMillis()));
|
||||
apiScenarioReport.setProjectId(apiScenario.getProjectId());
|
||||
apiScenarioReport.setTriggerMode(TaskTriggerMode.BATCH.name());
|
||||
|
@ -391,7 +326,7 @@ public class ApiScenarioBatchRunService {
|
|||
}
|
||||
|
||||
public ApiScenarioReport getScenarioReport(ApiRunModeConfigDTO runModeConfig, String userId) {
|
||||
ApiScenarioReport apiScenarioReport = apiScenarioService.getScenarioReport(userId);
|
||||
ApiScenarioReport apiScenarioReport = apiScenarioRunService.getScenarioReport(userId);
|
||||
apiScenarioReport.setEnvironmentId(runModeConfig.getEnvironmentId());
|
||||
apiScenarioReport.setRunMode(runModeConfig.getRunMode());
|
||||
apiScenarioReport.setPoolId(runModeConfig.getPoolId());
|
||||
|
@ -399,22 +334,7 @@ public class ApiScenarioBatchRunService {
|
|||
return apiScenarioReport;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取执行的环境ID
|
||||
* 优先使用运行配置的环境
|
||||
* 没有则使用用例自身的环境
|
||||
*
|
||||
* @param runModeConfig
|
||||
* @param apiScenario
|
||||
* @return
|
||||
*/
|
||||
public String getEnvId(ApiRunModeConfigDTO runModeConfig, ApiScenario apiScenario) {
|
||||
return StringUtils.isBlank(runModeConfig.getEnvironmentId()) ? apiScenario.getEnvironmentId() : runModeConfig.getEnvironmentId();
|
||||
}
|
||||
|
||||
public boolean getEnvGroup(ApiRunModeConfigDTO runModeConfig, ApiScenario apiScenario) {
|
||||
return StringUtils.isBlank(runModeConfig.getEnvironmentId()) ? apiScenario.getGrouped() : runModeConfig.getGrouped();
|
||||
}
|
||||
|
||||
public void updateStopOnFailureReport(ExecutionQueue queue) {
|
||||
ApiRunModeConfigDTO runModeConfig = queue.getRunModeConfig();
|
||||
|
@ -425,18 +345,18 @@ public class ApiScenarioBatchRunService {
|
|||
}
|
||||
long requestCount = 0L;
|
||||
while (queueDetail != null) {
|
||||
ApiScenarioDetail apiScenarioDetail = apiScenarioService.getForRun(queueDetail.getResourceId());
|
||||
ApiScenarioDetail apiScenarioDetail = apiScenarioRunService.getForRun(queueDetail.getResourceId());
|
||||
if (apiScenarioDetail == null) {
|
||||
LogUtils.info("当前场景已删除 {}", queueDetail.getResourceId());
|
||||
continue;
|
||||
}
|
||||
|
||||
Long requestCountItem = getRequestCount(apiScenarioDetail.getSteps());
|
||||
Long requestCountItem = apiScenarioRunService.getRequestCount(apiScenarioDetail.getSteps());
|
||||
requestCount += requestCountItem;
|
||||
|
||||
// 初始化报告步骤
|
||||
if (runModeConfig.isIntegratedReport()) {
|
||||
apiScenarioService.initScenarioReportSteps(apiScenarioDetail.getId(), apiScenarioDetail.getSteps(), runModeConfig.getCollectionReport().getReportId());
|
||||
apiScenarioRunService.initScenarioReportSteps(apiScenarioDetail.getId(), apiScenarioDetail.getSteps(), runModeConfig.getCollectionReport().getReportId());
|
||||
}
|
||||
|
||||
queueDetail = apiExecutionQueueService.getNextDetail(queue.getQueueId());
|
||||
|
|
|
@ -0,0 +1,961 @@
|
|||
package io.metersphere.api.service.scenario;
|
||||
|
||||
import io.metersphere.api.constants.ApiResourceType;
|
||||
import io.metersphere.api.constants.ApiScenarioStepRefType;
|
||||
import io.metersphere.api.constants.ApiScenarioStepType;
|
||||
import io.metersphere.api.domain.*;
|
||||
import io.metersphere.api.dto.*;
|
||||
import io.metersphere.api.dto.debug.ApiResourceRunRequest;
|
||||
import io.metersphere.api.dto.request.MsScenario;
|
||||
import io.metersphere.api.dto.request.controller.MsScriptElement;
|
||||
import io.metersphere.api.dto.request.http.MsHTTPElement;
|
||||
import io.metersphere.api.dto.scenario.*;
|
||||
import io.metersphere.api.mapper.ApiScenarioBlobMapper;
|
||||
import io.metersphere.api.mapper.ApiScenarioMapper;
|
||||
import io.metersphere.api.mapper.ApiScenarioReportMapper;
|
||||
import io.metersphere.api.parser.step.StepParser;
|
||||
import io.metersphere.api.parser.step.StepParserFactory;
|
||||
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;
|
||||
import io.metersphere.api.service.definition.ApiTestCaseService;
|
||||
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.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.service.EnvironmentGroupService;
|
||||
import io.metersphere.project.service.EnvironmentService;
|
||||
import io.metersphere.sdk.constants.ApiBatchRunMode;
|
||||
import io.metersphere.sdk.constants.ApiExecuteRunMode;
|
||||
import io.metersphere.sdk.constants.ExecStatus;
|
||||
import io.metersphere.sdk.constants.TaskTriggerMode;
|
||||
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.service.ApiPluginService;
|
||||
import io.metersphere.system.uid.IDGenerator;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class ApiScenarioRunService {
|
||||
@Resource
|
||||
private ApiScenarioMapper apiScenarioMapper;
|
||||
@Resource
|
||||
private ApiScenarioService apiScenarioService;
|
||||
@Resource
|
||||
private ApiExecuteService apiExecuteService;
|
||||
@Resource
|
||||
private ApiDefinitionService apiDefinitionService;
|
||||
@Resource
|
||||
private ApiTestCaseService apiTestCaseService;
|
||||
@Resource
|
||||
private EnvironmentService environmentService;
|
||||
@Resource
|
||||
private EnvironmentGroupService environmentGroupService;
|
||||
@Resource
|
||||
private ApiPluginService apiPluginService;
|
||||
@Resource
|
||||
private ApiDefinitionModuleService apiDefinitionModuleService;
|
||||
@Resource
|
||||
private ApiCommonService apiCommonService;
|
||||
@Resource
|
||||
private ApiScenarioReportService apiScenarioReportService;
|
||||
@Resource
|
||||
private ApiScenarioReportMapper apiScenarioReportMapper;
|
||||
@Resource
|
||||
private ApiScenarioBlobMapper apiScenarioBlobMapper;
|
||||
@Resource
|
||||
private ApiExecutionSetService apiExecutionSetService;
|
||||
|
||||
public TaskRequestDTO run(String id, String reportId, String userId) {
|
||||
ApiScenarioDetail apiScenarioDetail = getForRun(id);
|
||||
|
||||
// 解析生成待执行的场景树
|
||||
MsScenario msScenario = getMsScenario(apiScenarioDetail);
|
||||
|
||||
ApiScenarioParseParam parseParam = getApiScenarioParseParam(apiScenarioDetail);
|
||||
|
||||
return executeRun(apiScenarioDetail, msScenario, apiScenarioDetail.getSteps(), parseParam, new ApiResourceRunRequest(), reportId, userId);
|
||||
}
|
||||
|
||||
public TaskRequestDTO run(ApiScenarioDebugRequest request, String userId) {
|
||||
ApiScenario apiScenario = apiScenarioMapper.selectByPrimaryKey(request.getId());
|
||||
|
||||
// 解析生成待执行的场景树
|
||||
MsScenario msScenario = new MsScenario();
|
||||
msScenario.setRefType(ApiScenarioStepRefType.DIRECT.name());
|
||||
msScenario.setScenarioConfig(getScenarioConfig(request, true));
|
||||
msScenario.setProjectId(request.getProjectId());
|
||||
|
||||
// 处理特殊的步骤详情
|
||||
apiScenarioService.addSpecialStepDetails(request.getSteps(), request.getStepDetails());
|
||||
|
||||
ApiResourceRunRequest runRequest = new ApiResourceRunRequest();
|
||||
runRequest = setFileParam(request, runRequest);
|
||||
|
||||
return executeRun(apiScenario, msScenario, request.getSteps(), request, runRequest, request.getReportId(), userId);
|
||||
}
|
||||
|
||||
private ScenarioConfig getScenarioConfig(ApiScenarioDebugRequest request, boolean hasSave) {
|
||||
if (request.getScenarioConfig() != null) {
|
||||
// 优先使用前端传的配置
|
||||
return request.getScenarioConfig();
|
||||
} else if (hasSave) {
|
||||
// 没传并且保存过,则从数据库获取
|
||||
ApiScenarioBlob apiScenarioBlob = apiScenarioBlobMapper.selectByPrimaryKey(request.getId());
|
||||
if (apiScenarioBlob != null) {
|
||||
return JSON.parseObject(new String(apiScenarioBlob.getConfig()), ScenarioConfig.class);
|
||||
}
|
||||
}
|
||||
return new ScenarioConfig();
|
||||
}
|
||||
|
||||
public ApiScenarioParseParam getApiScenarioParseParam(ApiScenarioDetail apiScenarioDetail) {
|
||||
ApiScenarioParseParam parseParam = new ApiScenarioParseParam();
|
||||
parseParam.setScenarioConfig(apiScenarioDetail.getScenarioConfig());
|
||||
parseParam.setStepDetails(Map.of());
|
||||
parseParam.setEnvironmentId(apiScenarioDetail.getEnvironmentId());
|
||||
parseParam.setGrouped(apiScenarioDetail.getGrouped());
|
||||
return parseParam;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行时设置临时文件的相关参数
|
||||
*
|
||||
* @param request
|
||||
* @param runRequest
|
||||
*/
|
||||
private ApiResourceRunRequest setFileParam(ApiScenarioDebugRequest request, ApiResourceRunRequest runRequest) {
|
||||
runRequest.getLinkFileIds().addAll(getLinkFileIds(request.getFileParam()));
|
||||
runRequest.getUploadFileIds().addAll(getUploadFileIds(request.getFileParam()));
|
||||
Map<String, ResourceAddFileParam> stepFileParam = request.getStepFileParam();
|
||||
if (MapUtils.isNotEmpty(stepFileParam)) {
|
||||
stepFileParam.values().forEach(fileParam -> {
|
||||
runRequest.getLinkFileIds().addAll(getLinkFileIds(fileParam));
|
||||
runRequest.getUploadFileIds().addAll(getUploadFileIds(fileParam));
|
||||
});
|
||||
}
|
||||
return runRequest;
|
||||
}
|
||||
|
||||
public List<String> getLinkFileIds(ResourceAddFileParam fileParam) {
|
||||
if (fileParam != null && CollectionUtils.isNotEmpty(fileParam.getLinkFileIds())) {
|
||||
return fileParam.getLinkFileIds();
|
||||
}
|
||||
return List.of();
|
||||
}
|
||||
|
||||
public List<String> getUploadFileIds(ResourceAddFileParam fileParam) {
|
||||
if (fileParam != null && CollectionUtils.isNotEmpty(fileParam.getUploadFileIds())) {
|
||||
return fileParam.getUploadFileIds();
|
||||
}
|
||||
return List.of();
|
||||
}
|
||||
|
||||
public TaskRequestDTO executeRun(ApiScenario apiScenario,
|
||||
MsScenario msScenario,
|
||||
List<? extends ApiScenarioStepCommonDTO> steps,
|
||||
ApiScenarioParseParam parseParam,
|
||||
ApiResourceRunRequest runRequest,
|
||||
String reportId,
|
||||
String userId) {
|
||||
|
||||
msScenario.setResourceId(apiScenario.getId());
|
||||
|
||||
// 解析生成场景树,并保存临时变量
|
||||
ApiScenarioParseTmpParam tmpParam = parse(msScenario, steps, parseParam);
|
||||
|
||||
runRequest = setApiResourceRunRequestParam(msScenario, tmpParam, runRequest);
|
||||
|
||||
String poolId = apiExecuteService.getProjectApiResourcePoolId(apiScenario.getProjectId());
|
||||
|
||||
TaskRequestDTO taskRequest = getTaskRequest(reportId, apiScenario.getId(), apiScenario.getProjectId(), ApiExecuteRunMode.RUN.name());
|
||||
TaskInfo taskInfo = taskRequest.getTaskInfo();
|
||||
TaskItem taskItem = taskRequest.getTaskItem();
|
||||
taskInfo.getRunModeConfig().setPoolId(poolId);
|
||||
taskInfo.setSaveResult(true);
|
||||
taskInfo.getRunModeConfig().setEnvironmentId(parseParam.getEnvironmentId());
|
||||
taskRequest.getTaskItem().setRequestCount(tmpParam.getRequestCount().get());
|
||||
|
||||
if (StringUtils.isEmpty(taskItem.getReportId())) {
|
||||
taskInfo.setRealTime(false);
|
||||
reportId = IDGenerator.nextStr();
|
||||
taskItem.setReportId(reportId);
|
||||
} else {
|
||||
// 如果传了报告ID,则实时获取结果
|
||||
taskInfo.setRealTime(true);
|
||||
}
|
||||
|
||||
ApiScenarioParamConfig parseConfig = getApiScenarioParamConfig(apiScenario.getProjectId(), parseParam, tmpParam.getScenarioParseEnvInfo());
|
||||
parseConfig.setReportId(reportId);
|
||||
|
||||
// 初始化报告
|
||||
ApiScenarioReport scenarioReport = getScenarioReport(userId);
|
||||
scenarioReport.setId(reportId);
|
||||
scenarioReport.setTriggerMode(TaskTriggerMode.MANUAL.name());
|
||||
scenarioReport.setRunMode(ApiBatchRunMode.PARALLEL.name());
|
||||
scenarioReport.setPoolId(poolId);
|
||||
scenarioReport.setEnvironmentId(parseParam.getEnvironmentId());
|
||||
scenarioReport.setWaitingTime(getGlobalWaitTime(parseParam.getScenarioConfig()));
|
||||
|
||||
initApiReport(apiScenario, scenarioReport);
|
||||
|
||||
// 初始化报告步骤
|
||||
initScenarioReportSteps(steps, taskItem.getReportId());
|
||||
|
||||
return apiExecuteService.execute(runRequest, taskRequest, parseConfig);
|
||||
}
|
||||
|
||||
public MsScenario getMsScenario(ApiScenarioDetail apiScenarioDetail) {
|
||||
MsScenario msScenario = new MsScenario();
|
||||
msScenario.setRefType(ApiScenarioStepRefType.DIRECT.name());
|
||||
msScenario.setScenarioConfig(apiScenarioDetail.getScenarioConfig());
|
||||
msScenario.setProjectId(apiScenarioDetail.getProjectId());
|
||||
return msScenario;
|
||||
}
|
||||
|
||||
public ApiScenarioDetail getForRun(String scenarioId) {
|
||||
ApiScenarioDetail apiScenarioDetail = apiScenarioService.get(scenarioId);
|
||||
apiScenarioDetail.setSteps(filerDisableSteps(apiScenarioDetail.getSteps()));
|
||||
return apiScenarioDetail;
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤掉禁用的步骤
|
||||
*/
|
||||
public List<ApiScenarioStepDTO> filerDisableSteps(List<ApiScenarioStepDTO> steps) {
|
||||
if (CollectionUtils.isEmpty(steps)) {
|
||||
return List.of();
|
||||
}
|
||||
return steps.stream()
|
||||
.filter(step -> {
|
||||
boolean isEnable = BooleanUtils.isTrue(step.getEnable());
|
||||
if (isEnable) {
|
||||
step.setChildren(filerDisableSteps(step.getChildren()));
|
||||
}
|
||||
return isEnable;
|
||||
})
|
||||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析并返回执行脚本等信息
|
||||
*/
|
||||
public GetRunScriptResult getRunScript(GetRunScriptRequest request) {
|
||||
TaskItem taskItem = request.getTaskItem();
|
||||
String id = taskItem.getResourceId();
|
||||
ApiRunModeConfigDTO runModeConfig = request.getRunModeConfig();
|
||||
String reportId = taskItem.getReportId();
|
||||
|
||||
ApiScenarioDetail apiScenarioDetail = getForRun(id);
|
||||
if (apiScenarioDetail == null) {
|
||||
if (runModeConfig.isIntegratedReport()) {
|
||||
// 用例不存在,则在执行集合中删除
|
||||
apiExecutionSetService.removeItem(runModeConfig.getCollectionReport().getReportId(), id);
|
||||
}
|
||||
LogUtils.info("当前执行任务的用例已删除 {}", id);
|
||||
return null;
|
||||
}
|
||||
|
||||
String envId = getEnvId(runModeConfig, apiScenarioDetail);
|
||||
boolean envGroup = getEnvGroup(runModeConfig, apiScenarioDetail);
|
||||
|
||||
// 解析生成待执行的场景树
|
||||
MsScenario msScenario = getMsScenario(apiScenarioDetail);
|
||||
|
||||
ApiScenarioParseParam parseParam = getApiScenarioParseParam(apiScenarioDetail);
|
||||
parseParam.setEnvironmentId(envId);
|
||||
parseParam.setGrouped(envGroup);
|
||||
|
||||
// 初始化报告步骤
|
||||
if (runModeConfig.isIntegratedReport()) {
|
||||
initScenarioReportSteps(apiScenarioDetail.getId(), apiScenarioDetail.getSteps(), runModeConfig.getCollectionReport().getReportId());
|
||||
} else {
|
||||
updateReportWaitTime(reportId, parseParam);
|
||||
initScenarioReportSteps(apiScenarioDetail.getSteps(), reportId);
|
||||
}
|
||||
|
||||
GetRunScriptResult runScriptResult = new GetRunScriptResult();
|
||||
// 记录请求数量
|
||||
runScriptResult.setRequestCount(getRequestCount(apiScenarioDetail.getSteps()));
|
||||
|
||||
msScenario.setResourceId(apiScenarioDetail.getId());
|
||||
ApiScenarioParseTmpParam tmpParam = parse(msScenario, apiScenarioDetail.getSteps(), parseParam);
|
||||
|
||||
ApiResourceRunRequest runRequest = getApiResourceRunRequest(msScenario, tmpParam);
|
||||
|
||||
ApiScenarioParamConfig parseConfig = getApiScenarioParamConfig(apiScenarioDetail.getProjectId(), parseParam, tmpParam.getScenarioParseEnvInfo());
|
||||
parseConfig.setReportId(reportId);
|
||||
|
||||
String script = apiExecuteService.parseExecuteScript(runRequest.getTestElement(), parseConfig);
|
||||
|
||||
runScriptResult.setScript(script);
|
||||
|
||||
apiExecuteService.setTaskItemFileParam(runRequest, taskItem);
|
||||
|
||||
runScriptResult.setTaskResourceFile(taskItem.getTaskResourceFile());
|
||||
runScriptResult.setRefProjectResource(taskItem.getRefProjectResource());
|
||||
|
||||
return runScriptResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取执行的环境ID
|
||||
* 优先使用运行配置的环境
|
||||
* 没有则使用用例自身的环境
|
||||
*
|
||||
* @param runModeConfig
|
||||
* @param apiScenario
|
||||
* @return
|
||||
*/
|
||||
public String getEnvId(ApiRunModeConfigDTO runModeConfig, ApiScenario apiScenario) {
|
||||
return StringUtils.isBlank(runModeConfig.getEnvironmentId()) ? apiScenario.getEnvironmentId() : runModeConfig.getEnvironmentId();
|
||||
}
|
||||
|
||||
public boolean getEnvGroup(ApiRunModeConfigDTO runModeConfig, ApiScenario apiScenario) {
|
||||
return StringUtils.isBlank(runModeConfig.getEnvironmentId()) ? apiScenario.getGrouped() : runModeConfig.getGrouped();
|
||||
}
|
||||
|
||||
private void updateReportWaitTime(String reportId, ApiScenarioParseParam parseParam) {
|
||||
Long globalWaitTime = getGlobalWaitTime(parseParam.getScenarioConfig());
|
||||
if (globalWaitTime != null) {
|
||||
ApiScenarioReport apiScenarioReport = new ApiScenarioReport();
|
||||
apiScenarioReport.setId(reportId);
|
||||
apiScenarioReport.setWaitingTime(globalWaitTime);
|
||||
apiScenarioReportMapper.updateByPrimaryKeySelective(apiScenarioReport);
|
||||
}
|
||||
}
|
||||
|
||||
public TaskRequestDTO debug(ApiScenarioDebugRequest request) {
|
||||
ApiScenario apiScenario = apiScenarioMapper.selectByPrimaryKey(request.getId());
|
||||
boolean hasSave = apiScenario != null;
|
||||
|
||||
// 解析生成待执行的场景树
|
||||
MsScenario msScenario = new MsScenario();
|
||||
msScenario.setRefType(ApiScenarioStepRefType.DIRECT.name());
|
||||
msScenario.setScenarioConfig(getScenarioConfig(request, hasSave));
|
||||
msScenario.setProjectId(request.getProjectId());
|
||||
msScenario.setResourceId(request.getId());
|
||||
|
||||
// 处理特殊的步骤详情
|
||||
apiScenarioService.addSpecialStepDetails(request.getSteps(), request.getStepDetails());
|
||||
|
||||
ApiScenarioParseTmpParam tmpParam = parse(msScenario, request.getSteps(), request);
|
||||
|
||||
ApiResourceRunRequest runRequest = getApiResourceRunRequest(msScenario, tmpParam);
|
||||
|
||||
runRequest = setFileParam(request, runRequest);
|
||||
|
||||
TaskRequestDTO taskRequest = getTaskRequest(request.getReportId(), request.getId(), request.getProjectId(),
|
||||
apiExecuteService.getDebugRunModule(request.getFrontendDebug()));
|
||||
TaskInfo taskInfo = taskRequest.getTaskInfo();
|
||||
TaskItem taskItem = taskRequest.getTaskItem();
|
||||
taskInfo.setSaveResult(false);
|
||||
taskInfo.setRealTime(true);
|
||||
taskItem.setRequestCount(tmpParam.getRequestCount().get());
|
||||
|
||||
ApiScenarioParamConfig parseConfig = getApiScenarioParamConfig(request.getProjectId(), request, tmpParam.getScenarioParseEnvInfo());
|
||||
parseConfig.setReportId(request.getReportId());
|
||||
|
||||
|
||||
return apiExecuteService.execute(runRequest, taskRequest, parseConfig);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取场景前置的总等待时间
|
||||
*
|
||||
* @param scenarioConfig
|
||||
* @return
|
||||
*/
|
||||
public Long getGlobalWaitTime(ScenarioConfig scenarioConfig) {
|
||||
Long waitTime = null;
|
||||
if (scenarioConfig != null
|
||||
&& scenarioConfig.getPreProcessorConfig() != null
|
||||
&& scenarioConfig.getPreProcessorConfig().getProcessors() != null) {
|
||||
waitTime = 0L;
|
||||
for (MsProcessor processor : scenarioConfig
|
||||
.getPreProcessorConfig()
|
||||
.getProcessors()) {
|
||||
if (processor instanceof TimeWaitingProcessor timeWaitingProcessor
|
||||
&& timeWaitingProcessor.getEnable()
|
||||
&& timeWaitingProcessor.getDelay() != null) {
|
||||
waitTime += timeWaitingProcessor.getDelay();
|
||||
}
|
||||
}
|
||||
waitTime = waitTime > 0 ? waitTime : null;
|
||||
}
|
||||
return waitTime;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 预生成用例的执行报告
|
||||
*
|
||||
* @param apiScenario
|
||||
* @return
|
||||
*/
|
||||
public ApiScenarioRecord initApiReport(ApiScenario apiScenario, ApiScenarioReport scenarioReport) {
|
||||
// 初始化报告
|
||||
scenarioReport.setName(apiScenario.getName() + "_" + DateUtils.getTimeString(System.currentTimeMillis()));
|
||||
scenarioReport.setProjectId(apiScenario.getProjectId());
|
||||
|
||||
// 创建报告和用例的关联关系
|
||||
ApiScenarioRecord scenarioRecord = getApiScenarioRecord(apiScenario, scenarioReport);
|
||||
|
||||
apiScenarioReportService.insertApiScenarioReport(List.of(scenarioReport), List.of(scenarioRecord));
|
||||
return scenarioRecord;
|
||||
}
|
||||
|
||||
public Long getRequestCount(List<ApiScenarioStepDTO> steps) {
|
||||
AtomicLong requestCount = new AtomicLong();
|
||||
apiScenarioService.traversalStepTree(steps, step -> {
|
||||
if (BooleanUtils.isTrue(step.getEnable()) && apiScenarioService.isRequestStep(step)) {
|
||||
requestCount.getAndIncrement();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return requestCount.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化场景报告步骤
|
||||
*
|
||||
* @param steps
|
||||
* @param reportId
|
||||
*/
|
||||
public void initScenarioReportSteps(List<? extends ApiScenarioStepCommonDTO> steps, String reportId) {
|
||||
initScenarioReportSteps(null, steps, reportId);
|
||||
}
|
||||
|
||||
public void initScenarioReportSteps(String parentId, List<? extends ApiScenarioStepCommonDTO> steps, String reportId) {
|
||||
List<ApiScenarioReportStep> scenarioReportSteps = getScenarioReportSteps(parentId, steps, reportId);
|
||||
apiScenarioReportService.insertApiScenarioReportStep(scenarioReportSteps);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取场景报告步骤
|
||||
*
|
||||
* @param steps
|
||||
* @param reportId
|
||||
*/
|
||||
public List<ApiScenarioReportStep> getScenarioReportSteps(String parentId, List<? extends ApiScenarioStepCommonDTO> steps, String reportId) {
|
||||
AtomicLong sort = new AtomicLong(1);
|
||||
List<ApiScenarioReportStep> scenarioReportSteps = new ArrayList<>();
|
||||
for (ApiScenarioStepCommonDTO step : steps) {
|
||||
if (StringUtils.isBlank(step.getUniqueId())) {
|
||||
// 如果没有步骤唯一ID,则生成唯一ID
|
||||
step.setUniqueId(IDGenerator.nextStr());
|
||||
}
|
||||
ApiScenarioReportStep scenarioReportStep = getScenarioReportStep(step, reportId, sort.getAndIncrement());
|
||||
scenarioReportStep.setParentId(parentId);
|
||||
scenarioReportSteps.add(scenarioReportStep);
|
||||
List<? extends ApiScenarioStepCommonDTO> children = step.getChildren();
|
||||
if (CollectionUtils.isNotEmpty(children)) {
|
||||
scenarioReportSteps.addAll(getScenarioReportSteps(step.getUniqueId(), children, reportId));
|
||||
}
|
||||
}
|
||||
return scenarioReportSteps;
|
||||
}
|
||||
|
||||
private ApiScenarioReportStep getScenarioReportStep(ApiScenarioStepCommonDTO step, String reportId, long sort) {
|
||||
ApiScenarioReportStep scenarioReportStep = new ApiScenarioReportStep();
|
||||
scenarioReportStep.setReportId(reportId);
|
||||
scenarioReportStep.setStepId(step.getUniqueId());
|
||||
scenarioReportStep.setSort(sort);
|
||||
scenarioReportStep.setName(step.getName());
|
||||
scenarioReportStep.setStepType(step.getStepType());
|
||||
return scenarioReportStep;
|
||||
}
|
||||
|
||||
public ApiScenarioRecord getApiScenarioRecord(ApiScenario apiScenario, ApiScenarioReport scenarioReport) {
|
||||
ApiScenarioRecord scenarioRecord = new ApiScenarioRecord();
|
||||
scenarioRecord.setApiScenarioId(apiScenario.getId());
|
||||
scenarioRecord.setApiScenarioReportId(scenarioReport.getId());
|
||||
return scenarioRecord;
|
||||
}
|
||||
|
||||
|
||||
public ApiScenarioReport getScenarioReport(String userId) {
|
||||
ApiScenarioReport scenarioReport = new ApiScenarioReport();
|
||||
scenarioReport.setId(IDGenerator.nextStr());
|
||||
scenarioReport.setDeleted(false);
|
||||
scenarioReport.setIntegrated(false);
|
||||
scenarioReport.setExecStatus(ExecStatus.PENDING.name());
|
||||
scenarioReport.setStartTime(System.currentTimeMillis());
|
||||
scenarioReport.setUpdateTime(System.currentTimeMillis());
|
||||
scenarioReport.setUpdateUser(userId);
|
||||
scenarioReport.setCreateUser(userId);
|
||||
return scenarioReport;
|
||||
}
|
||||
|
||||
public ApiScenarioParamConfig getApiScenarioParamConfig(String projectId, ApiScenarioParseParam request, ApiScenarioParseEnvInfo scenarioParseEnvInfo) {
|
||||
ApiScenarioParamConfig parseConfig = new ApiScenarioParamConfig();
|
||||
parseConfig.setTestElementClassPluginIdMap(apiPluginService.getTestElementPluginMap());
|
||||
parseConfig.setTestElementClassProtocolMap(apiPluginService.getTestElementProtocolMap());
|
||||
parseConfig.setGrouped(request.getGrouped());
|
||||
parseConfig.setRootScenarioConfig(request.getScenarioConfig());
|
||||
if (BooleanUtils.isTrue(request.getGrouped())) {
|
||||
// 设置环境组 map
|
||||
parseConfig.setProjectEnvMap(getProjectEnvMap(scenarioParseEnvInfo, request.getEnvironmentId()));
|
||||
} else {
|
||||
// 设置环境
|
||||
parseConfig.setEnvConfig(scenarioParseEnvInfo.getEnvMap().get(request.getEnvironmentId()));
|
||||
}
|
||||
// 设置全局参数,接口调试不使用全局参数
|
||||
parseConfig.setGlobalParams(apiExecuteService.getGlobalParam(projectId));
|
||||
return parseConfig;
|
||||
}
|
||||
|
||||
public ApiResourceRunRequest getApiResourceRunRequest(MsScenario msScenario, ApiScenarioParseTmpParam tmpParam) {
|
||||
ApiResourceRunRequest runRequest = new ApiResourceRunRequest();
|
||||
return setApiResourceRunRequestParam(msScenario, tmpParam, runRequest);
|
||||
}
|
||||
|
||||
private ApiResourceRunRequest setApiResourceRunRequestParam(MsScenario msScenario, ApiScenarioParseTmpParam tmpParam, ApiResourceRunRequest runRequest) {
|
||||
runRequest.setFileResourceIds(tmpParam.getFileResourceIds());
|
||||
runRequest.setFileStepScenarioMap(tmpParam.getFileStepScenarioMap());
|
||||
runRequest.setRefProjectIds(tmpParam.getRefProjectIds());
|
||||
runRequest.setTestElement(msScenario);
|
||||
return runRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将步骤转换成场景树
|
||||
* 并保存临时变量
|
||||
*
|
||||
* @param msScenario
|
||||
* @param steps
|
||||
* @param parseParam
|
||||
* @return
|
||||
*/
|
||||
public ApiScenarioParseTmpParam parse(MsScenario msScenario,
|
||||
List<? extends ApiScenarioStepCommonDTO> steps,
|
||||
ApiScenarioParseParam parseParam) {
|
||||
// 记录引用的资源ID
|
||||
Map<String, List<String>> refResourceMap = new HashMap<>();
|
||||
buildRefResourceIdMap(steps, refResourceMap);
|
||||
|
||||
ApiScenarioParseTmpParam tmpParam = new ApiScenarioParseTmpParam();
|
||||
|
||||
// 查询引用的资源详情
|
||||
tmpParam.setResourceDetailMap(getResourceDetailMap(refResourceMap));
|
||||
|
||||
// 查询复制的步骤详情
|
||||
tmpParam.setStepDetailMap(getStepDetailMap(steps, parseParam.getStepDetails()));
|
||||
|
||||
// 获取场景环境相关配置
|
||||
tmpParam.setScenarioParseEnvInfo(getScenarioParseEnvInfo(refResourceMap, parseParam.getEnvironmentId(), parseParam.getGrouped()));
|
||||
parseStep2MsElement(msScenario, steps, tmpParam, msScenario.getResourceId());
|
||||
|
||||
// 设置 HttpElement 的模块信息
|
||||
setApiDefinitionExecuteInfo(tmpParam.getUniqueIdStepMap(), tmpParam.getStepTypeHttpElementMap());
|
||||
|
||||
// 设置使用脚本前后置的公共脚本信息
|
||||
apiCommonService.setCommonElementEnableCommonScriptInfo(tmpParam.getCommonElements());
|
||||
apiCommonService.setScriptElementEnableCommonScriptInfo(tmpParam.getScriptElements());
|
||||
|
||||
return tmpParam;
|
||||
}
|
||||
|
||||
private void buildRefResourceIdMap(List<? extends ApiScenarioStepCommonDTO> steps, Map<String, List<String>> refResourceIdMap) {
|
||||
for (ApiScenarioStepCommonDTO step : steps) {
|
||||
if (apiScenarioService.isRefOrPartialRef(step.getRefType()) && BooleanUtils.isTrue(step.getEnable())) {
|
||||
// 记录引用的步骤ID
|
||||
List<String> resourceIds = refResourceIdMap.computeIfAbsent(step.getStepType(), k -> new ArrayList<>());
|
||||
resourceIds.add(step.getResourceId());
|
||||
}
|
||||
|
||||
if (CollectionUtils.isNotEmpty(step.getChildren())) {
|
||||
buildRefResourceIdMap(step.getChildren(), refResourceIdMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, String> getStepDetailMap(List<? extends ApiScenarioStepCommonDTO> steps, Map<String, Object> stepDetailsParam) {
|
||||
List<String> needBlobStepIds = getHasDetailStepIds(steps, stepDetailsParam);
|
||||
Map<String, String> stepDetails = apiScenarioService.getStepBlobByIds(needBlobStepIds).stream()
|
||||
.collect(Collectors.toMap(ApiScenarioStepBlob::getId, blob -> new String(blob.getContent())));
|
||||
// 前端有传,就用前端传的
|
||||
if (stepDetailsParam != null) {
|
||||
stepDetailsParam.forEach((stepId, detail) -> stepDetails.put(stepId, detail instanceof byte[] bytes ? new String(bytes) : JSON.toJSONString(detail)));
|
||||
}
|
||||
return stepDetails;
|
||||
}
|
||||
|
||||
private List<String> getHasDetailStepIds(List<? extends ApiScenarioStepCommonDTO> steps, Map<String, Object> stepDetailsParam) {
|
||||
List<String> needBlobStepIds = new ArrayList<>();
|
||||
for (ApiScenarioStepCommonDTO step : steps) {
|
||||
List<? extends ApiScenarioStepCommonDTO> children = step.getChildren();
|
||||
if (CollectionUtils.isNotEmpty(children)) {
|
||||
needBlobStepIds.addAll(getHasDetailStepIds(children, stepDetailsParam));
|
||||
}
|
||||
if (BooleanUtils.isFalse(step.getEnable())) {
|
||||
continue;
|
||||
}
|
||||
if (!hasStepDetail(step.getStepType())) {
|
||||
continue;
|
||||
}
|
||||
if (stepDetailsParam != null && stepDetailsParam.containsKey(step.getId())) {
|
||||
// 前端传了blob,不需要再查
|
||||
continue;
|
||||
}
|
||||
needBlobStepIds.add(step.getId());
|
||||
}
|
||||
return needBlobStepIds;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 非完全引用的步骤和接口定义的步骤,才需要查 blob
|
||||
*
|
||||
* @param stepType
|
||||
* @return
|
||||
*/
|
||||
private boolean hasStepDetail(String stepType) {
|
||||
return !StringUtils.equals(stepType, ApiScenarioStepRefType.REF.name())
|
||||
|| apiScenarioService.isApi(stepType);
|
||||
}
|
||||
|
||||
private Map<String, String> getResourceDetailMap(Map<String, List<String>> refResourceMap) {
|
||||
Map<String, String> resourceBlobMap = new HashMap<>();
|
||||
List<String> apiIds = refResourceMap.get(ApiScenarioStepType.API.name());
|
||||
List<ApiDefinitionBlob> apiDefinitionBlobs = apiDefinitionService.getBlobByIds(apiIds);
|
||||
apiDefinitionBlobs.forEach(blob -> resourceBlobMap.put(blob.getId(), new String(blob.getRequest())));
|
||||
|
||||
List<String> apiCaseIds = refResourceMap.get(ApiScenarioStepType.API_CASE.name());
|
||||
List<ApiTestCaseBlob> apiTestCaseBlobs = apiTestCaseService.getBlobByIds(apiCaseIds);
|
||||
apiTestCaseBlobs.forEach(blob -> resourceBlobMap.put(blob.getId(), new String(blob.getRequest())));
|
||||
|
||||
List<String> apiScenarioIds = refResourceMap.get(ApiScenarioStepType.API_SCENARIO.name());
|
||||
List<ApiScenarioBlob> apiScenarioBlobs = getBlobByIds(apiScenarioIds);
|
||||
apiScenarioBlobs.forEach(blob -> resourceBlobMap.put(blob.getId(), new String(blob.getConfig())));
|
||||
return resourceBlobMap;
|
||||
}
|
||||
|
||||
private List<ApiScenarioBlob> getBlobByIds(List<String> apiScenarioIds) {
|
||||
if (CollectionUtils.isEmpty(apiScenarioIds)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
ApiScenarioBlobExample example = new ApiScenarioBlobExample();
|
||||
example.createCriteria().andIdIn(apiScenarioIds);
|
||||
return apiScenarioBlobMapper.selectByExampleWithBLOBs(example);
|
||||
}
|
||||
|
||||
public TaskRequestDTO getTaskRequest(String reportId, String resourceId, String projectId, String runModule) {
|
||||
TaskRequestDTO taskRequest = new TaskRequestDTO();
|
||||
TaskInfo taskInfo = getTaskInfo(projectId, runModule);
|
||||
TaskItem taskItem = apiExecuteService.getTaskItem(reportId, resourceId);
|
||||
taskRequest.setTaskInfo(taskInfo);
|
||||
taskRequest.setTaskItem(taskItem);
|
||||
return taskRequest;
|
||||
}
|
||||
|
||||
public TaskInfo getTaskInfo(String projectId, String runModule) {
|
||||
TaskInfo taskInfo = apiExecuteService.getTaskInfo(projectId);
|
||||
taskInfo.setResourceType(ApiResourceType.API_SCENARIO.name());
|
||||
taskInfo.setRunMode(runModule);
|
||||
return taskInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 HttpElement 的模块信息
|
||||
* 用户环境中的模块过滤
|
||||
*
|
||||
* @param uniqueIdStepMap
|
||||
* @param stepTypeHttpElementMap
|
||||
*/
|
||||
private void setApiDefinitionExecuteInfo(Map<String, ApiScenarioStepCommonDTO> uniqueIdStepMap, Map<String, List<MsHTTPElement>> stepTypeHttpElementMap) {
|
||||
setApiDefinitionExecuteInfo(uniqueIdStepMap, stepTypeHttpElementMap.get(ApiScenarioStepType.API.name()), apiDefinitionService::getModuleInfoByIds);
|
||||
setApiDefinitionExecuteInfo(uniqueIdStepMap, stepTypeHttpElementMap.get(ApiScenarioStepType.API_CASE.name()), apiTestCaseService::getModuleInfoByIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 MsHTTPElement 中的 method 等信息
|
||||
*
|
||||
* @param httpElements
|
||||
* @param getDefinitionInfoFunc
|
||||
*/
|
||||
public void setApiDefinitionExecuteInfo(Map<String, ApiScenarioStepCommonDTO> uniqueIdStepMap, List<MsHTTPElement> httpElements, Function<List<String>, List<ApiDefinitionExecuteInfo>> getDefinitionInfoFunc) {
|
||||
if (org.apache.commons.collections.CollectionUtils.isNotEmpty(httpElements)) {
|
||||
List<String> resourceIds = httpElements.stream().map(MsHTTPElement::getResourceId).collect(Collectors.toList());
|
||||
// 获取接口模块信息
|
||||
Map<String, ApiDefinitionExecuteInfo> resourceModuleMap = apiCommonService.getApiDefinitionExecuteInfoMap(getDefinitionInfoFunc, resourceIds);
|
||||
httpElements.forEach(httpElement -> {
|
||||
ApiDefinitionExecuteInfo definitionExecuteInfo = resourceModuleMap.get(httpElement.getResourceId());
|
||||
String path = httpElement.getPath();
|
||||
String method = httpElement.getMethod();
|
||||
|
||||
// httpElement 设置模块,请求方法等信息
|
||||
apiCommonService.setApiDefinitionExecuteInfo(httpElement, definitionExecuteInfo);
|
||||
|
||||
ApiScenarioStepCommonDTO step = uniqueIdStepMap.get(httpElement.getStepId());
|
||||
if (step != null && apiScenarioService.isCopyApi(step.getStepType(), step.getRefType())) {
|
||||
// 复制的接口定义,不使用源接口定义的path和method
|
||||
httpElement.setPath(path);
|
||||
httpElement.setMethod(method);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置脚本解析-环境相关参数
|
||||
*/
|
||||
private ApiScenarioParseEnvInfo getScenarioParseEnvInfo(Map<String, List<String>> refResourceMap, String currentEnvId, Boolean isCurrentEnvGrouped) {
|
||||
List<String> apiScenarioIds = refResourceMap.get(ApiScenarioStepType.API_SCENARIO.name());
|
||||
List<String> envIds = new ArrayList<>();
|
||||
List<String> envGroupIds = new ArrayList<>();
|
||||
ApiScenarioParseEnvInfo envInfo = new ApiScenarioParseEnvInfo();
|
||||
|
||||
if (BooleanUtils.isTrue(isCurrentEnvGrouped)) {
|
||||
envGroupIds.add(currentEnvId);
|
||||
} else {
|
||||
envIds.add(currentEnvId);
|
||||
}
|
||||
|
||||
if (CollectionUtils.isNotEmpty(apiScenarioIds)) {
|
||||
Map<String, EnvironmentModeDTO> refScenarioEnvMap = new HashMap<>();
|
||||
List<ApiScenario> apiScenarios = getApiScenarioByIds(apiScenarioIds);
|
||||
for (ApiScenario scenario : apiScenarios) {
|
||||
EnvironmentModeDTO envMode = new EnvironmentModeDTO();
|
||||
envMode.setEnvironmentId(scenario.getEnvironmentId());
|
||||
envMode.setGrouped(scenario.getGrouped());
|
||||
if (BooleanUtils.isTrue(scenario.getGrouped())) {
|
||||
// 记录环境组ID
|
||||
envGroupIds.add(scenario.getEnvironmentId());
|
||||
} else {
|
||||
// 记录环境ID
|
||||
envIds.add(scenario.getEnvironmentId());
|
||||
}
|
||||
// 保存场景的环境配置信息
|
||||
refScenarioEnvMap.put(scenario.getId(), envMode);
|
||||
}
|
||||
envInfo.setRefScenarioEnvMap(refScenarioEnvMap);
|
||||
}
|
||||
|
||||
// 查询环境组中的环境ID列表
|
||||
Map<String, List<String>> envGroupMap = new HashMap<>();
|
||||
environmentGroupService.getEnvironmentGroupRelations(envGroupIds).forEach(environmentGroupRelation -> {
|
||||
envGroupMap.putIfAbsent(environmentGroupRelation.getEnvironmentGroupId(), new ArrayList<>());
|
||||
envGroupMap.get(environmentGroupRelation.getEnvironmentGroupId()).add(environmentGroupRelation.getEnvironmentId());
|
||||
envIds.add(environmentGroupRelation.getEnvironmentId());
|
||||
});
|
||||
|
||||
// 获取环境的配置信息
|
||||
List<String> distinctEnvIds = envIds.stream().distinct().toList();
|
||||
Map<String, EnvironmentInfoDTO> envMap = environmentService.getByIds(distinctEnvIds)
|
||||
.stream()
|
||||
.collect(Collectors.toMap(EnvironmentInfoDTO::getId, Function.identity()));
|
||||
|
||||
envInfo.setEnvGroupMap(envGroupMap);
|
||||
envInfo.setEnvMap(envMap);
|
||||
|
||||
envMap.forEach((envId, envInfoDTO) -> handleHttpModuleMatchRule(envInfoDTO));
|
||||
|
||||
return envInfo;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 处理环境的 HTTP 配置模块匹配规则
|
||||
* 查询新增子模块
|
||||
*
|
||||
* @param envInfoDTO
|
||||
*/
|
||||
private void handleHttpModuleMatchRule(EnvironmentInfoDTO envInfoDTO) {
|
||||
List<HttpConfig> httpConfigs = envInfoDTO.getConfig().getHttpConfig();
|
||||
for (HttpConfig httpConfig : httpConfigs) {
|
||||
if (!httpConfig.isModuleMatchRule()) {
|
||||
continue;
|
||||
}
|
||||
// 获取勾选了包含子模块的模块ID
|
||||
HttpConfigModuleMatchRule moduleMatchRule = httpConfig.getModuleMatchRule();
|
||||
List<SelectModule> selectModules = moduleMatchRule.getModules();
|
||||
List<String> containChildModuleIds = selectModules.stream()
|
||||
.filter(SelectModule::getContainChildModule)
|
||||
.map(SelectModule::getModuleId)
|
||||
.toList();
|
||||
|
||||
// 查询子模块ID, 并去重
|
||||
Set<String> moduleIds = apiDefinitionModuleService.getModuleIdsByParentIds(containChildModuleIds)
|
||||
.stream()
|
||||
.collect(Collectors.toSet());
|
||||
selectModules.forEach(selectModule -> moduleIds.add(selectModule.getModuleId()));
|
||||
|
||||
// 重新设置选中的模块ID
|
||||
moduleMatchRule.setModules(null);
|
||||
List<SelectModule> allSelectModules = moduleIds.stream().map(moduleId -> {
|
||||
SelectModule module = new SelectModule();
|
||||
module.setModuleId(moduleId);
|
||||
return module;
|
||||
}).collect(Collectors.toList());
|
||||
moduleMatchRule.setModules(allSelectModules);
|
||||
}
|
||||
}
|
||||
|
||||
private List<ApiScenario> getApiScenarioByIds(List<String> apiScenarioIds) {
|
||||
ApiScenarioExample example = new ApiScenarioExample();
|
||||
example.createCriteria().andIdIn(apiScenarioIds);
|
||||
return apiScenarioMapper.selectByExample(example);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将步骤解析成 MsTestElement 树结构
|
||||
*/
|
||||
private void parseStep2MsElement(AbstractMsTestElement parentElement,
|
||||
List<? extends ApiScenarioStepCommonDTO> steps,
|
||||
ApiScenarioParseTmpParam parseParam,
|
||||
String scenarioId) {
|
||||
if (CollectionUtils.isNotEmpty(steps)) {
|
||||
parentElement.setChildren(new LinkedList<>());
|
||||
}
|
||||
|
||||
Map<String, String> stepDetailMap = parseParam.getStepDetailMap();
|
||||
Map<String, String> resourceDetailMap = parseParam.getResourceDetailMap();
|
||||
Map<String, List<MsHTTPElement>> stepTypeHttpElementMap = parseParam.getStepTypeHttpElementMap();
|
||||
for (ApiScenarioStepCommonDTO step : steps) {
|
||||
StepParser stepParser = StepParserFactory.getStepParser(step.getStepType());
|
||||
if (BooleanUtils.isFalse(step.getEnable())) {
|
||||
continue;
|
||||
}
|
||||
apiScenarioService.setPartialRefStepEnable(step, stepDetailMap);
|
||||
|
||||
if (apiScenarioService.isRequestStep(step) && BooleanUtils.isTrue(step.getEnable())) {
|
||||
// 记录待执行的请求总数
|
||||
parseParam.getRequestCount().getAndIncrement();
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(step.getUniqueId())) {
|
||||
// 如果调试的时候前端没有传步骤唯一ID,则生成唯一ID
|
||||
step.setUniqueId(IDGenerator.nextStr());
|
||||
}
|
||||
|
||||
parseParam.getUniqueIdStepMap().put(step.getUniqueId(), step);
|
||||
|
||||
// 将步骤详情解析生成对应的MsTestElement
|
||||
AbstractMsTestElement msTestElement = stepParser.parseTestElement(step,
|
||||
MapUtils.isNotEmpty(resourceDetailMap) ? resourceDetailMap.getOrDefault(step.getResourceId(), StringUtils.EMPTY) : StringUtils.EMPTY, stepDetailMap.get(step.getId()));
|
||||
if (msTestElement != null) {
|
||||
if (msTestElement instanceof MsHTTPElement msHTTPElement) {
|
||||
// 暂存http类型的步骤
|
||||
stepTypeHttpElementMap.putIfAbsent(step.getStepType(), new LinkedList<>());
|
||||
stepTypeHttpElementMap.get(step.getStepType()).add(msHTTPElement);
|
||||
} else if (msTestElement instanceof MsScriptElement msScriptElement) {
|
||||
parseParam.getScriptElements().add(msScriptElement);
|
||||
}
|
||||
msTestElement.setProjectId(step.getProjectId());
|
||||
msTestElement.setResourceId(step.getResourceId());
|
||||
msTestElement.setName(step.getName());
|
||||
// 步骤ID,设置为唯一ID
|
||||
msTestElement.setStepId(step.getUniqueId());
|
||||
msTestElement.setCsvIds(step.getCsvIds());
|
||||
|
||||
// 记录引用的资源ID和项目ID,下载执行文件时需要使用
|
||||
parseParam.getRefProjectIds().add(step.getProjectId());
|
||||
if (apiScenarioService.isRefOrPartialRef(step.getRefType())) {
|
||||
// 引用的步骤记录引用的资源ID
|
||||
parseParam.getFileResourceIds().add(step.getResourceId());
|
||||
} else if (msTestElement instanceof MsHTTPElement) {
|
||||
// 非引用的步骤记录步骤ID
|
||||
parseParam.getFileResourceIds().add(step.getId());
|
||||
parseParam.getFileStepScenarioMap().put(step.getId(), scenarioId);
|
||||
}
|
||||
|
||||
// 设置环境等,运行时场景参数
|
||||
setMsScenarioParam(parseParam.getScenarioParseEnvInfo(), step, msTestElement);
|
||||
|
||||
// 记录 msCommonElement
|
||||
Optional.ofNullable(apiCommonService.getMsCommonElement(msTestElement))
|
||||
.ifPresent(msCommonElement -> parseParam.getCommonElements().add(msCommonElement));
|
||||
// 组装树结构
|
||||
parentElement.getChildren().add(msTestElement);
|
||||
|
||||
if (CollectionUtils.isNotEmpty(step.getChildren())) {
|
||||
if (apiScenarioService.isScenarioStep(step.getStepType()) && apiScenarioService.isRefOrPartialRef(step.getRefType())) {
|
||||
scenarioId = step.getResourceId();
|
||||
}
|
||||
parseStep2MsElement(msTestElement, step.getChildren(), parseParam, scenarioId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置运行时场景参数
|
||||
*
|
||||
* @param scenarioParseEnvInfo
|
||||
* @param step
|
||||
* @param msTestElement
|
||||
*/
|
||||
private void setMsScenarioParam(ApiScenarioParseEnvInfo scenarioParseEnvInfo,
|
||||
ApiScenarioStepCommonDTO step,
|
||||
AbstractMsTestElement msTestElement) {
|
||||
// 引用的场景设置场景参数
|
||||
if (!apiScenarioService.isScenarioStep(step.getStepType()) || !apiScenarioService.isRefOrPartialRef(step.getRefType())
|
||||
|| !(msTestElement instanceof MsScenario msScenario)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (step.getConfig() != null) {
|
||||
// 设置场景步骤的运行参数
|
||||
msScenario.setScenarioStepConfig(JSON.parseObject(JSON.toJSONString(step.getConfig()), ScenarioStepConfig.class));
|
||||
}
|
||||
|
||||
// 获取当前场景配置的环境信息
|
||||
EnvironmentModeDTO environmentModeDTO = scenarioParseEnvInfo.getRefScenarioEnvMap().get(step.getResourceId());
|
||||
|
||||
if (environmentModeDTO != null) {
|
||||
String environmentId = environmentModeDTO.getEnvironmentId();
|
||||
|
||||
// 设置是否是环境组
|
||||
Boolean isGrouped = environmentModeDTO.getGrouped();
|
||||
msScenario.setGrouped(isGrouped);
|
||||
Map<String, EnvironmentInfoDTO> envMap = scenarioParseEnvInfo.getEnvMap();
|
||||
|
||||
if (BooleanUtils.isTrue(isGrouped)) {
|
||||
// 设置环境组 map
|
||||
msScenario.setProjectEnvMap(getProjectEnvMap(scenarioParseEnvInfo, environmentId));
|
||||
} else {
|
||||
// 设置环境
|
||||
msScenario.setEnvironmentInfo(envMap.get(environmentId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 scenarioParseEnvInfo 获取对应环境组的 projectEnvMap
|
||||
*
|
||||
* @param scenarioParseEnvInfo 环境信息
|
||||
* @param environmentId 环境ID
|
||||
* @return projectEnvMap
|
||||
*/
|
||||
private Map<String, EnvironmentInfoDTO> getProjectEnvMap(ApiScenarioParseEnvInfo scenarioParseEnvInfo, String environmentId) {
|
||||
Map<String, List<String>> envGroupMap = scenarioParseEnvInfo.getEnvGroupMap();
|
||||
List<String> envIds = envGroupMap.get(environmentId);
|
||||
Map<String, EnvironmentInfoDTO> projectEnvMap = new HashMap<>();
|
||||
for (String envId : envIds) {
|
||||
EnvironmentInfoDTO environmentInfoDTO = scenarioParseEnvInfo.getEnvMap().get(envId);
|
||||
projectEnvMap.put(environmentInfoDTO.getProjectId(), environmentInfoDTO);
|
||||
}
|
||||
return projectEnvMap;
|
||||
}
|
||||
}
|
|
@ -6,11 +6,9 @@ import io.metersphere.api.constants.ApiScenarioStepType;
|
|||
import io.metersphere.api.domain.*;
|
||||
import io.metersphere.api.dto.*;
|
||||
import io.metersphere.api.dto.debug.ApiFileResourceUpdateRequest;
|
||||
import io.metersphere.api.dto.debug.ApiResourceRunRequest;
|
||||
import io.metersphere.api.dto.definition.ExecutePageRequest;
|
||||
import io.metersphere.api.dto.definition.ExecuteReportDTO;
|
||||
import io.metersphere.api.dto.request.ApiTransferRequest;
|
||||
import io.metersphere.api.dto.request.MsScenario;
|
||||
import io.metersphere.api.dto.request.controller.MsScriptElement;
|
||||
import io.metersphere.api.dto.request.http.MsHTTPElement;
|
||||
import io.metersphere.api.dto.response.ApiScenarioBatchOperationResponse;
|
||||
|
@ -20,31 +18,23 @@ import io.metersphere.api.mapper.*;
|
|||
import io.metersphere.api.parser.step.StepParser;
|
||||
import io.metersphere.api.parser.step.StepParserFactory;
|
||||
import io.metersphere.api.service.ApiCommonService;
|
||||
import io.metersphere.api.service.ApiExecuteService;
|
||||
import io.metersphere.api.service.ApiFileResourceService;
|
||||
import io.metersphere.api.service.definition.ApiDefinitionModuleService;
|
||||
import io.metersphere.api.service.definition.ApiDefinitionService;
|
||||
import io.metersphere.api.service.definition.ApiTestCaseService;
|
||||
import io.metersphere.api.service.queue.ApiExecutionSetService;
|
||||
import io.metersphere.api.utils.ApiDataUtils;
|
||||
import io.metersphere.api.utils.ApiScenarioBatchOperationUtils;
|
||||
import io.metersphere.functional.domain.FunctionalCaseTestExample;
|
||||
import io.metersphere.functional.mapper.FunctionalCaseTestMapper;
|
||||
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.FileAssociation;
|
||||
import io.metersphere.project.domain.FileMetadata;
|
||||
import io.metersphere.project.domain.Project;
|
||||
import io.metersphere.project.domain.ProjectExample;
|
||||
import io.metersphere.project.dto.MoveNodeSortDTO;
|
||||
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.ExtBaseProjectVersionMapper;
|
||||
import io.metersphere.project.mapper.ProjectMapper;
|
||||
import io.metersphere.project.service.EnvironmentGroupService;
|
||||
import io.metersphere.project.service.EnvironmentService;
|
||||
import io.metersphere.project.service.MoveNodeService;
|
||||
import io.metersphere.sdk.constants.*;
|
||||
import io.metersphere.sdk.domain.Environment;
|
||||
|
@ -52,7 +42,6 @@ import io.metersphere.sdk.domain.EnvironmentExample;
|
|||
import io.metersphere.sdk.domain.EnvironmentGroup;
|
||||
import io.metersphere.sdk.domain.EnvironmentGroupExample;
|
||||
import io.metersphere.sdk.dto.api.task.ApiRunModeConfigDTO;
|
||||
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
|
||||
import io.metersphere.sdk.exception.MSException;
|
||||
import io.metersphere.sdk.file.FileCopyRequest;
|
||||
import io.metersphere.sdk.file.MinioRepository;
|
||||
|
@ -72,7 +61,6 @@ import io.metersphere.system.log.constants.OperationLogType;
|
|||
import io.metersphere.system.mapper.ScheduleMapper;
|
||||
import io.metersphere.system.notice.constants.NoticeConstants;
|
||||
import io.metersphere.system.schedule.ScheduleService;
|
||||
import io.metersphere.system.service.ApiPluginService;
|
||||
import io.metersphere.system.service.OperationHistoryService;
|
||||
import io.metersphere.system.service.UserLoginService;
|
||||
import io.metersphere.system.uid.IDGenerator;
|
||||
|
@ -149,8 +137,6 @@ public class ApiScenarioService extends MoveNodeService {
|
|||
@Resource
|
||||
private ApiScenarioBlobMapper apiScenarioBlobMapper;
|
||||
@Resource
|
||||
private ApiExecuteService apiExecuteService;
|
||||
@Resource
|
||||
private ApiDefinitionService apiDefinitionService;
|
||||
@Resource
|
||||
private ApiTestCaseService apiTestCaseService;
|
||||
|
@ -163,12 +149,6 @@ public class ApiScenarioService extends MoveNodeService {
|
|||
@Resource
|
||||
private ScheduleMapper scheduleMapper;
|
||||
@Resource
|
||||
private EnvironmentService environmentService;
|
||||
@Resource
|
||||
private EnvironmentGroupService environmentGroupService;
|
||||
@Resource
|
||||
private ApiPluginService apiPluginService;
|
||||
@Resource
|
||||
private ProjectMapper projectMapper;
|
||||
@Resource
|
||||
private ExtApiDefinitionMapper extApiDefinitionMapper;
|
||||
|
@ -179,14 +159,10 @@ public class ApiScenarioService extends MoveNodeService {
|
|||
@Resource
|
||||
private ExtApiTestCaseMapper extApiTestCaseMapper;
|
||||
@Resource
|
||||
private ApiDefinitionModuleService apiDefinitionModuleService;
|
||||
@Resource
|
||||
private OperationHistoryService operationHistoryService;
|
||||
@Resource
|
||||
private ApiCommonService apiCommonService;
|
||||
@Resource
|
||||
private ApiScenarioReportService apiScenarioReportService;
|
||||
@Resource
|
||||
private ApiScenarioReportMapper apiScenarioReportMapper;
|
||||
@Resource
|
||||
private ApiScenarioNoticeService apiScenarioNoticeService;
|
||||
|
@ -930,7 +906,7 @@ public class ApiScenarioService extends MoveNodeService {
|
|||
return StringUtils.equals(refType, ApiScenarioStepRefType.PARTIAL_REF.name());
|
||||
}
|
||||
|
||||
private boolean isRefOrPartialRef(String refType) {
|
||||
public boolean isRefOrPartialRef(String refType) {
|
||||
return StringUtils.equalsAny(refType, ApiScenarioStepRefType.REF.name(), ApiScenarioStepRefType.PARTIAL_REF.name());
|
||||
}
|
||||
|
||||
|
@ -1005,7 +981,7 @@ public class ApiScenarioService extends MoveNodeService {
|
|||
* copyFromStepId 的 detail
|
||||
* isNew 的资源的 detail
|
||||
*/
|
||||
private void addSpecialStepDetails(List<ApiScenarioStepRequest> steps, Map<String, Object> stepDetails) {
|
||||
public void addSpecialStepDetails(List<ApiScenarioStepRequest> steps, Map<String, Object> stepDetails) {
|
||||
if (CollectionUtils.isEmpty(steps)) {
|
||||
return;
|
||||
}
|
||||
|
@ -1338,625 +1314,19 @@ public class ApiScenarioService extends MoveNodeService {
|
|||
return ServiceUtils.checkResourceExist(apiScenarioMapper.selectByPrimaryKey(id), "permission.system_api_scenario.name");
|
||||
}
|
||||
|
||||
public TaskRequestDTO debug(ApiScenarioDebugRequest request) {
|
||||
ApiScenario apiScenario = apiScenarioMapper.selectByPrimaryKey(request.getId());
|
||||
boolean hasSave = apiScenario != null;
|
||||
|
||||
// 解析生成待执行的场景树
|
||||
MsScenario msScenario = new MsScenario();
|
||||
msScenario.setRefType(ApiScenarioStepRefType.DIRECT.name());
|
||||
msScenario.setScenarioConfig(getScenarioConfig(request, hasSave));
|
||||
msScenario.setProjectId(request.getProjectId());
|
||||
msScenario.setResourceId(request.getId());
|
||||
|
||||
// 处理特殊的步骤详情
|
||||
addSpecialStepDetails(request.getSteps(), request.getStepDetails());
|
||||
|
||||
ApiScenarioParseTmpParam tmpParam = parse(msScenario, request.getSteps(), request);
|
||||
|
||||
ApiResourceRunRequest runRequest = getApiResourceRunRequest(msScenario, tmpParam);
|
||||
|
||||
runRequest = setFileParam(request, runRequest);
|
||||
|
||||
TaskRequestDTO taskRequest = getTaskRequest(request.getReportId(), request.getId(), request.getProjectId(),
|
||||
apiExecuteService.getDebugRunModule(request.getFrontendDebug()));
|
||||
taskRequest.setSaveResult(false);
|
||||
taskRequest.setRealTime(true);
|
||||
taskRequest.setRequestCount(tmpParam.getRequestCount().get());
|
||||
|
||||
ApiScenarioParamConfig parseConfig = getApiScenarioParamConfig(request, tmpParam.getScenarioParseEnvInfo());
|
||||
parseConfig.setReportId(request.getReportId());
|
||||
|
||||
return apiExecuteService.execute(runRequest, taskRequest, parseConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行时设置临时文件的相关参数
|
||||
*
|
||||
* @param request
|
||||
* @param runRequest
|
||||
*/
|
||||
private ApiResourceRunRequest setFileParam(ApiScenarioDebugRequest request, ApiResourceRunRequest runRequest) {
|
||||
runRequest.getLinkFileIds().addAll(getLinkFileIds(request.getFileParam()));
|
||||
runRequest.getUploadFileIds().addAll(getUploadFileIds(request.getFileParam()));
|
||||
Map<String, ResourceAddFileParam> stepFileParam = request.getStepFileParam();
|
||||
if (MapUtils.isNotEmpty(stepFileParam)) {
|
||||
stepFileParam.values().forEach(fileParam -> {
|
||||
runRequest.getLinkFileIds().addAll(getLinkFileIds(fileParam));
|
||||
runRequest.getUploadFileIds().addAll(getUploadFileIds(fileParam));
|
||||
});
|
||||
}
|
||||
return runRequest;
|
||||
}
|
||||
|
||||
public List<String> getLinkFileIds(ResourceAddFileParam fileParam) {
|
||||
if (fileParam != null && CollectionUtils.isNotEmpty(fileParam.getLinkFileIds())) {
|
||||
return fileParam.getLinkFileIds();
|
||||
}
|
||||
return List.of();
|
||||
}
|
||||
|
||||
public List<String> getUploadFileIds(ResourceAddFileParam fileParam) {
|
||||
if (fileParam != null && CollectionUtils.isNotEmpty(fileParam.getUploadFileIds())) {
|
||||
return fileParam.getUploadFileIds();
|
||||
}
|
||||
return List.of();
|
||||
}
|
||||
|
||||
public TaskRequestDTO run(String id, String reportId, String userId) {
|
||||
ApiScenarioDetail apiScenarioDetail = getForRun(id);
|
||||
|
||||
// 解析生成待执行的场景树
|
||||
MsScenario msScenario = getMsScenario(apiScenarioDetail);
|
||||
|
||||
ApiScenarioParseParam parseParam = getApiScenarioParseParam(apiScenarioDetail);
|
||||
|
||||
return executeRun(apiScenarioDetail, msScenario, apiScenarioDetail.getSteps(), parseParam, new ApiResourceRunRequest(), reportId, userId);
|
||||
}
|
||||
|
||||
public ApiScenarioParseParam getApiScenarioParseParam(ApiScenarioDetail apiScenarioDetail) {
|
||||
ApiScenarioParseParam parseParam = new ApiScenarioParseParam();
|
||||
parseParam.setScenarioConfig(apiScenarioDetail.getScenarioConfig());
|
||||
parseParam.setStepDetails(Map.of());
|
||||
parseParam.setEnvironmentId(apiScenarioDetail.getEnvironmentId());
|
||||
parseParam.setGrouped(apiScenarioDetail.getGrouped());
|
||||
return parseParam;
|
||||
}
|
||||
|
||||
public MsScenario getMsScenario(ApiScenarioDetail apiScenarioDetail) {
|
||||
MsScenario msScenario = new MsScenario();
|
||||
msScenario.setRefType(ApiScenarioStepRefType.DIRECT.name());
|
||||
msScenario.setScenarioConfig(apiScenarioDetail.getScenarioConfig());
|
||||
msScenario.setProjectId(apiScenarioDetail.getProjectId());
|
||||
return msScenario;
|
||||
}
|
||||
|
||||
public TaskRequestDTO run(ApiScenarioDebugRequest request, String userId) {
|
||||
ApiScenario apiScenario = apiScenarioMapper.selectByPrimaryKey(request.getId());
|
||||
|
||||
// 解析生成待执行的场景树
|
||||
MsScenario msScenario = new MsScenario();
|
||||
msScenario.setRefType(ApiScenarioStepRefType.DIRECT.name());
|
||||
msScenario.setScenarioConfig(getScenarioConfig(request, true));
|
||||
msScenario.setProjectId(request.getProjectId());
|
||||
|
||||
// 处理特殊的步骤详情
|
||||
addSpecialStepDetails(request.getSteps(), request.getStepDetails());
|
||||
|
||||
ApiResourceRunRequest runRequest = new ApiResourceRunRequest();
|
||||
runRequest = setFileParam(request, runRequest);
|
||||
|
||||
return executeRun(apiScenario, msScenario, request.getSteps(), request, runRequest, request.getReportId(), userId);
|
||||
}
|
||||
|
||||
public TaskRequestDTO executeRun(ApiScenario apiScenario,
|
||||
MsScenario msScenario,
|
||||
List<? extends ApiScenarioStepCommonDTO> steps,
|
||||
ApiScenarioParseParam parseParam,
|
||||
ApiResourceRunRequest runRequest,
|
||||
String reportId,
|
||||
String userId) {
|
||||
|
||||
msScenario.setResourceId(apiScenario.getId());
|
||||
|
||||
// 解析生成场景树,并保存临时变量
|
||||
ApiScenarioParseTmpParam tmpParam = parse(msScenario, steps, parseParam);
|
||||
|
||||
runRequest = setApiResourceRunRequestParam(msScenario, tmpParam, runRequest);
|
||||
|
||||
String poolId = apiExecuteService.getProjectApiResourcePoolId(apiScenario.getProjectId());
|
||||
|
||||
TaskRequestDTO taskRequest = getTaskRequest(reportId, apiScenario.getId(), apiScenario.getProjectId(), ApiExecuteRunMode.RUN.name());
|
||||
taskRequest.getRunModeConfig().setPoolId(poolId);
|
||||
taskRequest.setSaveResult(true);
|
||||
taskRequest.getRunModeConfig().setEnvironmentId(parseParam.getEnvironmentId());
|
||||
taskRequest.setRequestCount(tmpParam.getRequestCount().get());
|
||||
|
||||
if (StringUtils.isEmpty(taskRequest.getReportId())) {
|
||||
taskRequest.setRealTime(false);
|
||||
reportId = IDGenerator.nextStr();
|
||||
taskRequest.setReportId(reportId);
|
||||
} else {
|
||||
// 如果传了报告ID,则实时获取结果
|
||||
taskRequest.setRealTime(true);
|
||||
}
|
||||
|
||||
ApiScenarioParamConfig parseConfig = getApiScenarioParamConfig(parseParam, tmpParam.getScenarioParseEnvInfo());
|
||||
parseConfig.setReportId(reportId);
|
||||
|
||||
// 初始化报告
|
||||
ApiScenarioReport scenarioReport = getScenarioReport(userId);
|
||||
scenarioReport.setId(reportId);
|
||||
scenarioReport.setTriggerMode(TaskTriggerMode.MANUAL.name());
|
||||
scenarioReport.setRunMode(ApiBatchRunMode.PARALLEL.name());
|
||||
scenarioReport.setPoolId(poolId);
|
||||
scenarioReport.setEnvironmentId(parseParam.getEnvironmentId());
|
||||
scenarioReport.setWaitingTime(getGlobalWaitTime(parseParam.getScenarioConfig()));
|
||||
|
||||
initApiReport(apiScenario, scenarioReport);
|
||||
|
||||
// 初始化报告步骤
|
||||
initScenarioReportSteps(steps, taskRequest.getReportId());
|
||||
|
||||
return apiExecuteService.execute(runRequest, taskRequest, parseConfig);
|
||||
}
|
||||
|
||||
public boolean isRequestStep(ApiScenarioStepCommonDTO step) {
|
||||
ApiScenarioStepType scenarioStepType = EnumValidator.validateEnum(ApiScenarioStepType.class, step.getStepType());
|
||||
return scenarioStepType == null ? false : scenarioStepType.isRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* 预生成用例的执行报告
|
||||
*
|
||||
* @param apiScenario
|
||||
* @return
|
||||
*/
|
||||
public ApiScenarioRecord initApiReport(ApiScenario apiScenario, ApiScenarioReport scenarioReport) {
|
||||
// 初始化报告
|
||||
scenarioReport.setName(apiScenario.getName() + "_" + DateUtils.getTimeString(System.currentTimeMillis()));
|
||||
scenarioReport.setProjectId(apiScenario.getProjectId());
|
||||
|
||||
// 创建报告和用例的关联关系
|
||||
ApiScenarioRecord scenarioRecord = getApiScenarioRecord(apiScenario, scenarioReport);
|
||||
|
||||
apiScenarioReportService.insertApiScenarioReport(List.of(scenarioReport), List.of(scenarioRecord));
|
||||
return scenarioRecord;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化场景报告步骤
|
||||
*
|
||||
* @param steps
|
||||
* @param reportId
|
||||
*/
|
||||
public void initScenarioReportSteps(List<? extends ApiScenarioStepCommonDTO> steps, String reportId) {
|
||||
initScenarioReportSteps(null, steps, reportId);
|
||||
}
|
||||
|
||||
public void initScenarioReportSteps(String parentId, List<? extends ApiScenarioStepCommonDTO> steps, String reportId) {
|
||||
List<ApiScenarioReportStep> scenarioReportSteps = getScenarioReportSteps(parentId, steps, reportId);
|
||||
apiScenarioReportService.insertApiScenarioReportStep(scenarioReportSteps);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取场景报告步骤
|
||||
*
|
||||
* @param steps
|
||||
* @param reportId
|
||||
*/
|
||||
public List<ApiScenarioReportStep> getScenarioReportSteps(String parentId, List<? extends ApiScenarioStepCommonDTO> steps, String reportId) {
|
||||
AtomicLong sort = new AtomicLong(1);
|
||||
List<ApiScenarioReportStep> scenarioReportSteps = new ArrayList<>();
|
||||
for (ApiScenarioStepCommonDTO step : steps) {
|
||||
if (StringUtils.isBlank(step.getUniqueId())) {
|
||||
// 如果没有步骤唯一ID,则生成唯一ID
|
||||
step.setUniqueId(IDGenerator.nextStr());
|
||||
}
|
||||
ApiScenarioReportStep scenarioReportStep = getScenarioReportStep(step, reportId, sort.getAndIncrement());
|
||||
scenarioReportStep.setParentId(parentId);
|
||||
scenarioReportSteps.add(scenarioReportStep);
|
||||
List<? extends ApiScenarioStepCommonDTO> children = step.getChildren();
|
||||
if (CollectionUtils.isNotEmpty(children)) {
|
||||
scenarioReportSteps.addAll(getScenarioReportSteps(step.getUniqueId(), children, reportId));
|
||||
}
|
||||
}
|
||||
return scenarioReportSteps;
|
||||
}
|
||||
|
||||
private ApiScenarioReportStep getScenarioReportStep(ApiScenarioStepCommonDTO step, String reportId, long sort) {
|
||||
ApiScenarioReportStep scenarioReportStep = new ApiScenarioReportStep();
|
||||
scenarioReportStep.setReportId(reportId);
|
||||
scenarioReportStep.setStepId(step.getUniqueId());
|
||||
scenarioReportStep.setSort(sort);
|
||||
scenarioReportStep.setName(step.getName());
|
||||
scenarioReportStep.setStepType(step.getStepType());
|
||||
return scenarioReportStep;
|
||||
}
|
||||
|
||||
public ApiScenarioRecord getApiScenarioRecord(ApiScenario apiScenario, ApiScenarioReport scenarioReport) {
|
||||
ApiScenarioRecord scenarioRecord = new ApiScenarioRecord();
|
||||
scenarioRecord.setApiScenarioId(apiScenario.getId());
|
||||
scenarioRecord.setApiScenarioReportId(scenarioReport.getId());
|
||||
return scenarioRecord;
|
||||
}
|
||||
|
||||
public ApiScenarioReport getScenarioReport(String userId) {
|
||||
ApiScenarioReport scenarioReport = new ApiScenarioReport();
|
||||
scenarioReport.setId(IDGenerator.nextStr());
|
||||
scenarioReport.setDeleted(false);
|
||||
scenarioReport.setIntegrated(false);
|
||||
scenarioReport.setExecStatus(ExecStatus.PENDING.name());
|
||||
scenarioReport.setStartTime(System.currentTimeMillis());
|
||||
scenarioReport.setUpdateTime(System.currentTimeMillis());
|
||||
scenarioReport.setUpdateUser(userId);
|
||||
scenarioReport.setCreateUser(userId);
|
||||
return scenarioReport;
|
||||
}
|
||||
|
||||
public ApiScenarioParamConfig getApiScenarioParamConfig(ApiScenarioParseParam request, ApiScenarioParseEnvInfo scenarioParseEnvInfo) {
|
||||
ApiScenarioParamConfig parseConfig = new ApiScenarioParamConfig();
|
||||
parseConfig.setTestElementClassPluginIdMap(apiPluginService.getTestElementPluginMap());
|
||||
parseConfig.setTestElementClassProtocolMap(apiPluginService.getTestElementProtocolMap());
|
||||
parseConfig.setGrouped(request.getGrouped());
|
||||
parseConfig.setRootScenarioConfig(request.getScenarioConfig());
|
||||
if (BooleanUtils.isTrue(request.getGrouped())) {
|
||||
// 设置环境组 map
|
||||
parseConfig.setProjectEnvMap(getProjectEnvMap(scenarioParseEnvInfo, request.getEnvironmentId()));
|
||||
} else {
|
||||
// 设置环境
|
||||
parseConfig.setEnvConfig(scenarioParseEnvInfo.getEnvMap().get(request.getEnvironmentId()));
|
||||
}
|
||||
return parseConfig;
|
||||
}
|
||||
|
||||
public ApiResourceRunRequest getApiResourceRunRequest(MsScenario msScenario, ApiScenarioParseTmpParam tmpParam) {
|
||||
ApiResourceRunRequest runRequest = new ApiResourceRunRequest();
|
||||
return setApiResourceRunRequestParam(msScenario, tmpParam, runRequest);
|
||||
}
|
||||
|
||||
private ApiResourceRunRequest setApiResourceRunRequestParam(MsScenario msScenario, ApiScenarioParseTmpParam tmpParam, ApiResourceRunRequest runRequest) {
|
||||
runRequest.setFileResourceIds(tmpParam.getFileResourceIds());
|
||||
runRequest.setFileStepScenarioMap(tmpParam.getFileStepScenarioMap());
|
||||
runRequest.setRefProjectIds(tmpParam.getRefProjectIds());
|
||||
runRequest.setTestElement(msScenario);
|
||||
return runRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将步骤转换成场景树
|
||||
* 并保存临时变量
|
||||
*
|
||||
* @param msScenario
|
||||
* @param steps
|
||||
* @param parseParam
|
||||
* @return
|
||||
*/
|
||||
public ApiScenarioParseTmpParam parse(MsScenario msScenario,
|
||||
List<? extends ApiScenarioStepCommonDTO> steps,
|
||||
ApiScenarioParseParam parseParam) {
|
||||
// 记录引用的资源ID
|
||||
Map<String, List<String>> refResourceMap = new HashMap<>();
|
||||
buildRefResourceIdMap(steps, refResourceMap);
|
||||
|
||||
ApiScenarioParseTmpParam tmpParam = new ApiScenarioParseTmpParam();
|
||||
|
||||
// 查询引用的资源详情
|
||||
tmpParam.setResourceDetailMap(getResourceDetailMap(refResourceMap));
|
||||
|
||||
// 查询复制的步骤详情
|
||||
tmpParam.setStepDetailMap(getStepDetailMap(steps, parseParam.getStepDetails()));
|
||||
|
||||
// 获取场景环境相关配置
|
||||
tmpParam.setScenarioParseEnvInfo(getScenarioParseEnvInfo(refResourceMap, parseParam.getEnvironmentId(), parseParam.getGrouped()));
|
||||
parseStep2MsElement(msScenario, steps, tmpParam, msScenario.getResourceId());
|
||||
|
||||
// 设置 HttpElement 的模块信息
|
||||
setApiDefinitionExecuteInfo(tmpParam.getUniqueIdStepMap(), tmpParam.getStepTypeHttpElementMap());
|
||||
|
||||
// 设置使用脚本前后置的公共脚本信息
|
||||
apiCommonService.setCommonElementEnableCommonScriptInfo(tmpParam.getCommonElements());
|
||||
apiCommonService.setScriptElementEnableCommonScriptInfo(tmpParam.getScriptElements());
|
||||
|
||||
return tmpParam;
|
||||
}
|
||||
|
||||
public TaskRequestDTO getTaskRequest(String reportId, String resourceId, String projectId, String runModule) {
|
||||
TaskRequestDTO taskRequest = apiExecuteService.getTaskRequest(reportId, resourceId, projectId);
|
||||
taskRequest.setResourceType(ApiResourceType.API_SCENARIO.name());
|
||||
taskRequest.setRunMode(runModule);
|
||||
return taskRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 HttpElement 的模块信息
|
||||
* 用户环境中的模块过滤
|
||||
*
|
||||
* @param uniqueIdStepMap
|
||||
* @param stepTypeHttpElementMap
|
||||
*/
|
||||
private void setApiDefinitionExecuteInfo(Map<String, ApiScenarioStepCommonDTO> uniqueIdStepMap, Map<String, List<MsHTTPElement>> stepTypeHttpElementMap) {
|
||||
setApiDefinitionExecuteInfo(uniqueIdStepMap, stepTypeHttpElementMap.get(ApiScenarioStepType.API.name()), apiDefinitionService::getModuleInfoByIds);
|
||||
setApiDefinitionExecuteInfo(uniqueIdStepMap, stepTypeHttpElementMap.get(ApiScenarioStepType.API_CASE.name()), apiTestCaseService::getModuleInfoByIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 MsHTTPElement 中的 method 等信息
|
||||
*
|
||||
* @param httpElements
|
||||
* @param getDefinitionInfoFunc
|
||||
*/
|
||||
public void setApiDefinitionExecuteInfo(Map<String, ApiScenarioStepCommonDTO> uniqueIdStepMap, List<MsHTTPElement> httpElements, Function<List<String>, List<ApiDefinitionExecuteInfo>> getDefinitionInfoFunc) {
|
||||
if (org.apache.commons.collections.CollectionUtils.isNotEmpty(httpElements)) {
|
||||
List<String> resourceIds = httpElements.stream().map(MsHTTPElement::getResourceId).collect(Collectors.toList());
|
||||
// 获取接口模块信息
|
||||
Map<String, ApiDefinitionExecuteInfo> resourceModuleMap = apiCommonService.getApiDefinitionExecuteInfoMap(getDefinitionInfoFunc, resourceIds);
|
||||
httpElements.forEach(httpElement -> {
|
||||
ApiDefinitionExecuteInfo definitionExecuteInfo = resourceModuleMap.get(httpElement.getResourceId());
|
||||
String path = httpElement.getPath();
|
||||
String method = httpElement.getMethod();
|
||||
|
||||
// httpElement 设置模块,请求方法等信息
|
||||
apiCommonService.setApiDefinitionExecuteInfo(httpElement, definitionExecuteInfo);
|
||||
|
||||
ApiScenarioStepCommonDTO step = uniqueIdStepMap.get(httpElement.getStepId());
|
||||
if (step != null && isCopyApi(step.getStepType(), step.getRefType())) {
|
||||
// 复制的接口定义,不使用源接口定义的path和method
|
||||
httpElement.setPath(path);
|
||||
httpElement.setMethod(method);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置脚本解析-环境相关参数
|
||||
*/
|
||||
private ApiScenarioParseEnvInfo getScenarioParseEnvInfo(Map<String, List<String>> refResourceMap, String currentEnvId, Boolean isCurrentEnvGrouped) {
|
||||
List<String> apiScenarioIds = refResourceMap.get(ApiScenarioStepType.API_SCENARIO.name());
|
||||
List<String> envIds = new ArrayList<>();
|
||||
List<String> envGroupIds = new ArrayList<>();
|
||||
ApiScenarioParseEnvInfo envInfo = new ApiScenarioParseEnvInfo();
|
||||
|
||||
if (BooleanUtils.isTrue(isCurrentEnvGrouped)) {
|
||||
envGroupIds.add(currentEnvId);
|
||||
} else {
|
||||
envIds.add(currentEnvId);
|
||||
}
|
||||
|
||||
if (CollectionUtils.isNotEmpty(apiScenarioIds)) {
|
||||
Map<String, EnvironmentModeDTO> refScenarioEnvMap = new HashMap<>();
|
||||
List<ApiScenario> apiScenarios = getApiScenarioByIds(apiScenarioIds);
|
||||
for (ApiScenario scenario : apiScenarios) {
|
||||
EnvironmentModeDTO envMode = new EnvironmentModeDTO();
|
||||
envMode.setEnvironmentId(scenario.getEnvironmentId());
|
||||
envMode.setGrouped(scenario.getGrouped());
|
||||
if (BooleanUtils.isTrue(scenario.getGrouped())) {
|
||||
// 记录环境组ID
|
||||
envGroupIds.add(scenario.getEnvironmentId());
|
||||
} else {
|
||||
// 记录环境ID
|
||||
envIds.add(scenario.getEnvironmentId());
|
||||
}
|
||||
// 保存场景的环境配置信息
|
||||
refScenarioEnvMap.put(scenario.getId(), envMode);
|
||||
}
|
||||
envInfo.setRefScenarioEnvMap(refScenarioEnvMap);
|
||||
}
|
||||
|
||||
// 查询环境组中的环境ID列表
|
||||
Map<String, List<String>> envGroupMap = new HashMap<>();
|
||||
environmentGroupService.getEnvironmentGroupRelations(envGroupIds).forEach(environmentGroupRelation -> {
|
||||
envGroupMap.putIfAbsent(environmentGroupRelation.getEnvironmentGroupId(), new ArrayList<>());
|
||||
envGroupMap.get(environmentGroupRelation.getEnvironmentGroupId()).add(environmentGroupRelation.getEnvironmentId());
|
||||
envIds.add(environmentGroupRelation.getEnvironmentId());
|
||||
});
|
||||
|
||||
// 获取环境的配置信息
|
||||
List<String> distinctEnvIds = envIds.stream().distinct().toList();
|
||||
Map<String, EnvironmentInfoDTO> envMap = environmentService.getByIds(distinctEnvIds)
|
||||
.stream()
|
||||
.collect(Collectors.toMap(EnvironmentInfoDTO::getId, Function.identity()));
|
||||
|
||||
envInfo.setEnvGroupMap(envGroupMap);
|
||||
envInfo.setEnvMap(envMap);
|
||||
|
||||
envMap.forEach((envId, envInfoDTO) -> handleHttpModuleMatchRule(envInfoDTO));
|
||||
|
||||
return envInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理环境的 HTTP 配置模块匹配规则
|
||||
* 查询新增子模块
|
||||
*
|
||||
* @param envInfoDTO
|
||||
*/
|
||||
private void handleHttpModuleMatchRule(EnvironmentInfoDTO envInfoDTO) {
|
||||
List<HttpConfig> httpConfigs = envInfoDTO.getConfig().getHttpConfig();
|
||||
for (HttpConfig httpConfig : httpConfigs) {
|
||||
if (!httpConfig.isModuleMatchRule()) {
|
||||
continue;
|
||||
}
|
||||
// 获取勾选了包含子模块的模块ID
|
||||
HttpConfigModuleMatchRule moduleMatchRule = httpConfig.getModuleMatchRule();
|
||||
List<SelectModule> selectModules = moduleMatchRule.getModules();
|
||||
List<String> containChildModuleIds = selectModules.stream()
|
||||
.filter(SelectModule::getContainChildModule)
|
||||
.map(SelectModule::getModuleId)
|
||||
.toList();
|
||||
|
||||
// 查询子模块ID, 并去重
|
||||
Set<String> moduleIds = apiDefinitionModuleService.getModuleIdsByParentIds(containChildModuleIds)
|
||||
.stream()
|
||||
.collect(Collectors.toSet());
|
||||
selectModules.forEach(selectModule -> moduleIds.add(selectModule.getModuleId()));
|
||||
|
||||
// 重新设置选中的模块ID
|
||||
moduleMatchRule.setModules(null);
|
||||
List<SelectModule> allSelectModules = moduleIds.stream().map(moduleId -> {
|
||||
SelectModule module = new SelectModule();
|
||||
module.setModuleId(moduleId);
|
||||
return module;
|
||||
}).collect(Collectors.toList());
|
||||
moduleMatchRule.setModules(allSelectModules);
|
||||
}
|
||||
}
|
||||
|
||||
private List<ApiScenario> getApiScenarioByIds(List<String> apiScenarioIds) {
|
||||
ApiScenarioExample example = new ApiScenarioExample();
|
||||
example.createCriteria().andIdIn(apiScenarioIds);
|
||||
return apiScenarioMapper.selectByExample(example);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将步骤解析成 MsTestElement 树结构
|
||||
*/
|
||||
private void parseStep2MsElement(AbstractMsTestElement parentElement,
|
||||
List<? extends ApiScenarioStepCommonDTO> steps,
|
||||
ApiScenarioParseTmpParam parseParam,
|
||||
String scenarioId) {
|
||||
if (CollectionUtils.isNotEmpty(steps)) {
|
||||
parentElement.setChildren(new LinkedList<>());
|
||||
}
|
||||
|
||||
Map<String, String> stepDetailMap = parseParam.getStepDetailMap();
|
||||
Map<String, String> resourceDetailMap = parseParam.getResourceDetailMap();
|
||||
Map<String, List<MsHTTPElement>> stepTypeHttpElementMap = parseParam.getStepTypeHttpElementMap();
|
||||
for (ApiScenarioStepCommonDTO step : steps) {
|
||||
StepParser stepParser = StepParserFactory.getStepParser(step.getStepType());
|
||||
if (BooleanUtils.isFalse(step.getEnable())) {
|
||||
continue;
|
||||
}
|
||||
setPartialRefStepEnable(step, stepDetailMap);
|
||||
|
||||
if (isRequestStep(step) && BooleanUtils.isTrue(step.getEnable())) {
|
||||
// 记录待执行的请求总数
|
||||
parseParam.getRequestCount().getAndIncrement();
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(step.getUniqueId())) {
|
||||
// 如果调试的时候前端没有传步骤唯一ID,则生成唯一ID
|
||||
step.setUniqueId(IDGenerator.nextStr());
|
||||
}
|
||||
|
||||
parseParam.getUniqueIdStepMap().put(step.getUniqueId(), step);
|
||||
|
||||
// 将步骤详情解析生成对应的MsTestElement
|
||||
AbstractMsTestElement msTestElement = stepParser.parseTestElement(step,
|
||||
MapUtils.isNotEmpty(resourceDetailMap) ? resourceDetailMap.getOrDefault(step.getResourceId(), StringUtils.EMPTY) : StringUtils.EMPTY, stepDetailMap.get(step.getId()));
|
||||
if (msTestElement != null) {
|
||||
if (msTestElement instanceof MsHTTPElement msHTTPElement) {
|
||||
// 暂存http类型的步骤
|
||||
stepTypeHttpElementMap.putIfAbsent(step.getStepType(), new LinkedList<>());
|
||||
stepTypeHttpElementMap.get(step.getStepType()).add(msHTTPElement);
|
||||
} else if (msTestElement instanceof MsScriptElement msScriptElement) {
|
||||
parseParam.getScriptElements().add(msScriptElement);
|
||||
}
|
||||
msTestElement.setProjectId(step.getProjectId());
|
||||
msTestElement.setResourceId(step.getResourceId());
|
||||
msTestElement.setName(step.getName());
|
||||
// 步骤ID,设置为唯一ID
|
||||
msTestElement.setStepId(step.getUniqueId());
|
||||
msTestElement.setCsvIds(step.getCsvIds());
|
||||
|
||||
// 记录引用的资源ID和项目ID,下载执行文件时需要使用
|
||||
parseParam.getRefProjectIds().add(step.getProjectId());
|
||||
if (isRefOrPartialRef(step.getRefType())) {
|
||||
// 引用的步骤记录引用的资源ID
|
||||
parseParam.getFileResourceIds().add(step.getResourceId());
|
||||
} else if (msTestElement instanceof MsHTTPElement) {
|
||||
// 非引用的步骤记录步骤ID
|
||||
parseParam.getFileResourceIds().add(step.getId());
|
||||
parseParam.getFileStepScenarioMap().put(step.getId(), scenarioId);
|
||||
}
|
||||
|
||||
// 设置环境等,运行时场景参数
|
||||
setMsScenarioParam(parseParam.getScenarioParseEnvInfo(), step, msTestElement);
|
||||
|
||||
// 记录 msCommonElement
|
||||
Optional.ofNullable(apiCommonService.getMsCommonElement(msTestElement))
|
||||
.ifPresent(msCommonElement -> parseParam.getCommonElements().add(msCommonElement));
|
||||
// 组装树结构
|
||||
parentElement.getChildren().add(msTestElement);
|
||||
|
||||
if (CollectionUtils.isNotEmpty(step.getChildren())) {
|
||||
if (isScenarioStep(step.getStepType()) && isRefOrPartialRef(step.getRefType())) {
|
||||
scenarioId = step.getResourceId();
|
||||
}
|
||||
parseStep2MsElement(msTestElement, step.getChildren(), parseParam, scenarioId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置运行时场景参数
|
||||
*
|
||||
* @param scenarioParseEnvInfo
|
||||
* @param step
|
||||
* @param msTestElement
|
||||
*/
|
||||
private void setMsScenarioParam(ApiScenarioParseEnvInfo scenarioParseEnvInfo,
|
||||
ApiScenarioStepCommonDTO step,
|
||||
AbstractMsTestElement msTestElement) {
|
||||
// 引用的场景设置场景参数
|
||||
if (!isScenarioStep(step.getStepType()) || !isRefOrPartialRef(step.getRefType()) || !(msTestElement instanceof MsScenario msScenario)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (step.getConfig() != null) {
|
||||
// 设置场景步骤的运行参数
|
||||
msScenario.setScenarioStepConfig(JSON.parseObject(JSON.toJSONString(step.getConfig()), ScenarioStepConfig.class));
|
||||
}
|
||||
|
||||
// 获取当前场景配置的环境信息
|
||||
EnvironmentModeDTO environmentModeDTO = scenarioParseEnvInfo.getRefScenarioEnvMap().get(step.getResourceId());
|
||||
|
||||
if (environmentModeDTO != null) {
|
||||
String environmentId = environmentModeDTO.getEnvironmentId();
|
||||
|
||||
// 设置是否是环境组
|
||||
Boolean isGrouped = environmentModeDTO.getGrouped();
|
||||
msScenario.setGrouped(isGrouped);
|
||||
Map<String, EnvironmentInfoDTO> envMap = scenarioParseEnvInfo.getEnvMap();
|
||||
|
||||
if (BooleanUtils.isTrue(isGrouped)) {
|
||||
// 设置环境组 map
|
||||
msScenario.setProjectEnvMap(getProjectEnvMap(scenarioParseEnvInfo, environmentId));
|
||||
} else {
|
||||
// 设置环境
|
||||
msScenario.setEnvironmentInfo(envMap.get(environmentId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 scenarioParseEnvInfo 获取对应环境组的 projectEnvMap
|
||||
*
|
||||
* @param scenarioParseEnvInfo 环境信息
|
||||
* @param environmentId 环境ID
|
||||
* @return projectEnvMap
|
||||
*/
|
||||
private Map<String, EnvironmentInfoDTO> getProjectEnvMap(ApiScenarioParseEnvInfo scenarioParseEnvInfo, String environmentId) {
|
||||
Map<String, List<String>> envGroupMap = scenarioParseEnvInfo.getEnvGroupMap();
|
||||
List<String> envIds = envGroupMap.get(environmentId);
|
||||
Map<String, EnvironmentInfoDTO> projectEnvMap = new HashMap<>();
|
||||
for (String envId : envIds) {
|
||||
EnvironmentInfoDTO environmentInfoDTO = scenarioParseEnvInfo.getEnvMap().get(envId);
|
||||
projectEnvMap.put(environmentInfoDTO.getProjectId(), environmentInfoDTO);
|
||||
}
|
||||
return projectEnvMap;
|
||||
}
|
||||
|
||||
private static boolean isScenarioStep(String stepType) {
|
||||
public static boolean isScenarioStep(String stepType) {
|
||||
return StringUtils.equals(stepType, ApiScenarioStepType.API_SCENARIO.name());
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置单个部分引用的步骤的启用状态
|
||||
*/
|
||||
private void setPartialRefStepEnable(ApiScenarioStepCommonDTO step, Map<String, String> stepDetailMap) {
|
||||
public void setPartialRefStepEnable(ApiScenarioStepCommonDTO step, Map<String, String> stepDetailMap) {
|
||||
String stepDetail = stepDetailMap.get(step.getId());
|
||||
if (!isPartialRef(step) || StringUtils.isBlank(stepDetail)) {
|
||||
return;
|
||||
|
@ -1998,17 +1368,6 @@ public class ApiScenarioService extends MoveNodeService {
|
|||
StringUtils.equals(step.getRefType(), ApiScenarioStepRefType.PARTIAL_REF.name());
|
||||
}
|
||||
|
||||
private Map<String, String> getStepDetailMap(List<? extends ApiScenarioStepCommonDTO> steps, Map<String, Object> stepDetailsParam) {
|
||||
List<String> needBlobStepIds = getHasDetailStepIds(steps, stepDetailsParam);
|
||||
Map<String, String> stepDetails = getStepBlobByIds(needBlobStepIds).stream()
|
||||
.collect(Collectors.toMap(ApiScenarioStepBlob::getId, blob -> new String(blob.getContent())));
|
||||
// 前端有传,就用前端传的
|
||||
if (stepDetailsParam != null) {
|
||||
stepDetailsParam.forEach((stepId, detail) -> stepDetails.put(stepId, detail instanceof byte[] bytes ? new String(bytes) : JSON.toJSONString(detail)));
|
||||
}
|
||||
return stepDetails;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询部分引用的步骤的详情
|
||||
*
|
||||
|
@ -2031,56 +1390,7 @@ public class ApiScenarioService extends MoveNodeService {
|
|||
.collect(Collectors.toMap(ApiScenarioStepBlob::getId, blob -> new String(blob.getContent())));
|
||||
}
|
||||
|
||||
private List<String> getHasDetailStepIds(List<? extends ApiScenarioStepCommonDTO> steps, Map<String, Object> stepDetailsParam) {
|
||||
List<String> needBlobStepIds = new ArrayList<>();
|
||||
for (ApiScenarioStepCommonDTO step : steps) {
|
||||
List<? extends ApiScenarioStepCommonDTO> children = step.getChildren();
|
||||
if (CollectionUtils.isNotEmpty(children)) {
|
||||
needBlobStepIds.addAll(getHasDetailStepIds(children, stepDetailsParam));
|
||||
}
|
||||
if (BooleanUtils.isFalse(step.getEnable())) {
|
||||
continue;
|
||||
}
|
||||
if (!hasStepDetail(step.getStepType())) {
|
||||
continue;
|
||||
}
|
||||
if (stepDetailsParam != null && stepDetailsParam.containsKey(step.getId())) {
|
||||
// 前端传了blob,不需要再查
|
||||
continue;
|
||||
}
|
||||
needBlobStepIds.add(step.getId());
|
||||
}
|
||||
return needBlobStepIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 非完全引用的步骤和接口定义的步骤,才需要查 blob
|
||||
*
|
||||
* @param stepType
|
||||
* @return
|
||||
*/
|
||||
private boolean hasStepDetail(String stepType) {
|
||||
return !StringUtils.equals(stepType, ApiScenarioStepRefType.REF.name())
|
||||
|| isApi(stepType);
|
||||
}
|
||||
|
||||
private Map<String, String> getResourceDetailMap(Map<String, List<String>> refResourceMap) {
|
||||
Map<String, String> resourceBlobMap = new HashMap<>();
|
||||
List<String> apiIds = refResourceMap.get(ApiScenarioStepType.API.name());
|
||||
List<ApiDefinitionBlob> apiDefinitionBlobs = apiDefinitionService.getBlobByIds(apiIds);
|
||||
apiDefinitionBlobs.forEach(blob -> resourceBlobMap.put(blob.getId(), new String(blob.getRequest())));
|
||||
|
||||
List<String> apiCaseIds = refResourceMap.get(ApiScenarioStepType.API_CASE.name());
|
||||
List<ApiTestCaseBlob> apiTestCaseBlobs = apiTestCaseService.getBlobByIds(apiCaseIds);
|
||||
apiTestCaseBlobs.forEach(blob -> resourceBlobMap.put(blob.getId(), new String(blob.getRequest())));
|
||||
|
||||
List<String> apiScenarioIds = refResourceMap.get(ApiScenarioStepType.API_SCENARIO.name());
|
||||
List<ApiScenarioBlob> apiScenarioBlobs = getBlobByIds(apiScenarioIds);
|
||||
apiScenarioBlobs.forEach(blob -> resourceBlobMap.put(blob.getId(), new String(blob.getConfig())));
|
||||
return resourceBlobMap;
|
||||
}
|
||||
|
||||
private List<ApiScenarioStepBlob> getStepBlobByIds(List<String> stepIds) {
|
||||
public List<ApiScenarioStepBlob> getStepBlobByIds(List<String> stepIds) {
|
||||
if (CollectionUtils.isEmpty(stepIds)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
@ -2089,43 +1399,6 @@ public class ApiScenarioService extends MoveNodeService {
|
|||
return apiScenarioStepBlobMapper.selectByExampleWithBLOBs(example);
|
||||
}
|
||||
|
||||
private List<ApiScenarioBlob> getBlobByIds(List<String> apiScenarioIds) {
|
||||
if (CollectionUtils.isEmpty(apiScenarioIds)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
ApiScenarioBlobExample example = new ApiScenarioBlobExample();
|
||||
example.createCriteria().andIdIn(apiScenarioIds);
|
||||
return apiScenarioBlobMapper.selectByExampleWithBLOBs(example);
|
||||
}
|
||||
|
||||
private void buildRefResourceIdMap(List<? extends ApiScenarioStepCommonDTO> steps, Map<String, List<String>> refResourceIdMap) {
|
||||
for (ApiScenarioStepCommonDTO step : steps) {
|
||||
if (isRefOrPartialRef(step.getRefType()) && BooleanUtils.isTrue(step.getEnable())) {
|
||||
// 记录引用的步骤ID
|
||||
List<String> resourceIds = refResourceIdMap.computeIfAbsent(step.getStepType(), k -> new ArrayList<>());
|
||||
resourceIds.add(step.getResourceId());
|
||||
}
|
||||
|
||||
if (CollectionUtils.isNotEmpty(step.getChildren())) {
|
||||
buildRefResourceIdMap(step.getChildren(), refResourceIdMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ScenarioConfig getScenarioConfig(ApiScenarioDebugRequest request, boolean hasSave) {
|
||||
if (request.getScenarioConfig() != null) {
|
||||
// 优先使用前端传的配置
|
||||
return request.getScenarioConfig();
|
||||
} else if (hasSave) {
|
||||
// 没传并且保存过,则从数据库获取
|
||||
ApiScenarioBlob apiScenarioBlob = apiScenarioBlobMapper.selectByPrimaryKey(request.getId());
|
||||
if (apiScenarioBlob != null) {
|
||||
return JSON.parseObject(new String(apiScenarioBlob.getConfig()), ScenarioConfig.class);
|
||||
}
|
||||
}
|
||||
return new ScenarioConfig();
|
||||
}
|
||||
|
||||
public void updateStatus(String id, String status, String userId) {
|
||||
checkResourceExist(id);
|
||||
ApiScenario update = new ApiScenario();
|
||||
|
@ -2181,36 +1454,6 @@ public class ApiScenarioService extends MoveNodeService {
|
|||
return apiScenarios.getFirst();
|
||||
}
|
||||
|
||||
public ApiScenarioDetail getForRun(String scenarioId) {
|
||||
ApiScenarioDetail apiScenarioDetail = get(scenarioId);
|
||||
apiScenarioDetail.setSteps(filerDisableSteps(apiScenarioDetail.getSteps()));
|
||||
return apiScenarioDetail;
|
||||
}
|
||||
|
||||
public List<ApiScenarioDetail> getForRuns(List<String> scenarioIds) {
|
||||
List<ApiScenarioDetail> apiScenarioDetails = list(scenarioIds);
|
||||
apiScenarioDetails.forEach(apiScenarioDetail -> apiScenarioDetail.setSteps(filerDisableSteps(apiScenarioDetail.getSteps())));
|
||||
return apiScenarioDetails;
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤掉禁用的步骤
|
||||
*/
|
||||
public List<ApiScenarioStepDTO> filerDisableSteps(List<ApiScenarioStepDTO> steps) {
|
||||
if (CollectionUtils.isEmpty(steps)) {
|
||||
return List.of();
|
||||
}
|
||||
return steps.stream()
|
||||
.filter(step -> {
|
||||
boolean isEnable = BooleanUtils.isTrue(step.getEnable());
|
||||
if (isEnable) {
|
||||
step.setChildren(filerDisableSteps(step.getChildren()));
|
||||
}
|
||||
return isEnable;
|
||||
})
|
||||
.toList();
|
||||
}
|
||||
|
||||
public ApiScenarioDetail get(String scenarioId) {
|
||||
ApiScenario apiScenario = checkResourceIsNoDeleted(scenarioId);
|
||||
ApiScenarioDetail apiScenarioDetail = BeanUtils.copyBean(new ApiScenarioDetail(), apiScenario);
|
||||
|
@ -2397,19 +1640,19 @@ public class ApiScenarioService extends MoveNodeService {
|
|||
* 判断步骤是否是引用的接口定义
|
||||
* 引用的接口定义允许修改参数值,需要特殊处理
|
||||
*/
|
||||
private boolean isCopyApi(String stepType, String refType) {
|
||||
public boolean isCopyApi(String stepType, String refType) {
|
||||
return isApi(stepType) && isCopy(refType);
|
||||
}
|
||||
|
||||
private boolean isApi(String stepType) {
|
||||
public boolean isApi(String stepType) {
|
||||
return StringUtils.equals(stepType, ApiScenarioStepType.API.name());
|
||||
}
|
||||
|
||||
private boolean isCopy(String refType) {
|
||||
public boolean isCopy(String refType) {
|
||||
return StringUtils.equals(refType, ApiScenarioStepRefType.COPY.name());
|
||||
}
|
||||
|
||||
private boolean isApiCase(String stepType) {
|
||||
public boolean isApiCase(String stepType) {
|
||||
return StringUtils.equals(stepType, ApiScenarioStepType.API_CASE.name());
|
||||
}
|
||||
|
||||
|
@ -3110,6 +2353,7 @@ public class ApiScenarioService extends MoveNodeService {
|
|||
resourceInfo.setDelete(apiTestCase.getDeleted());
|
||||
resourceInfo.setProjectId(apiTestCase.getProjectId());
|
||||
});
|
||||
default -> {}
|
||||
}
|
||||
Optional.ofNullable(apiStepResourceInfo).ifPresent(resourceInfo -> {
|
||||
Project project = projectMapper.selectByPrimaryKey(resourceInfo.getProjectId());
|
||||
|
@ -3128,30 +2372,4 @@ public class ApiScenarioService extends MoveNodeService {
|
|||
setParamFunc.accept(apiStepResourceInfo, resource);
|
||||
return apiStepResourceInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取场景前置的总等待时间
|
||||
*
|
||||
* @param scenarioConfig
|
||||
* @return
|
||||
*/
|
||||
public Long getGlobalWaitTime(ScenarioConfig scenarioConfig) {
|
||||
Long waitTime = null;
|
||||
if (scenarioConfig != null
|
||||
&& scenarioConfig.getPreProcessorConfig() != null
|
||||
&& scenarioConfig.getPreProcessorConfig().getProcessors() != null) {
|
||||
waitTime = 0L;
|
||||
for (MsProcessor processor : scenarioConfig
|
||||
.getPreProcessorConfig()
|
||||
.getProcessors()) {
|
||||
if (processor instanceof TimeWaitingProcessor timeWaitingProcessor
|
||||
&& timeWaitingProcessor.getEnable()
|
||||
&& timeWaitingProcessor.getDelay() != null) {
|
||||
waitTime += timeWaitingProcessor.getDelay();
|
||||
}
|
||||
}
|
||||
waitTime = waitTime > 0 ? waitTime : null;
|
||||
}
|
||||
return waitTime;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
package io.metersphere.api.utils;
|
||||
|
||||
import io.metersphere.api.dto.scenario.ApiScenarioDetail;
|
||||
import io.metersphere.api.service.scenario.ApiScenarioBatchRunService;
|
||||
import io.metersphere.sdk.dto.api.task.ApiRunModeConfigDTO;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class ExecTask implements Runnable {
|
||||
private ApiScenarioBatchRunService apiScenarioBatchRunService;
|
||||
private ApiScenarioDetail detail;
|
||||
private Map<String, String> scenarioReportMap;
|
||||
private ApiRunModeConfigDTO runModeConfig;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
apiScenarioBatchRunService.execute(detail, scenarioReportMap, runModeConfig);
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
package io.metersphere.api.utils;
|
||||
|
||||
import io.metersphere.sdk.util.LogUtils;
|
||||
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class TaskRunnerUtils {
|
||||
|
||||
// 线程池维护线程的最大数量
|
||||
private final static int MAX_POOL_SIZE = 10;
|
||||
// 线程池维护线程所允许的空闲时间
|
||||
private final static int KEEP_ALIVE_TIME = 1;
|
||||
// 线程池所使用的缓冲队列大小
|
||||
private final static int WORK_QUEUE_SIZE = 50000;
|
||||
|
||||
private static final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
|
||||
MAX_POOL_SIZE,
|
||||
MAX_POOL_SIZE,
|
||||
KEEP_ALIVE_TIME,
|
||||
TimeUnit.SECONDS,
|
||||
new ArrayBlockingQueue<>(WORK_QUEUE_SIZE));
|
||||
|
||||
public static void executeThreadPool(ExecTask task) {
|
||||
try {
|
||||
// 开始执行任务
|
||||
threadPool.execute(task);
|
||||
|
||||
LogUtils.info("当前线程池活跃线程数量:{},当前线程池线程数量:{},当前线程池队列数量:{}",
|
||||
threadPool.getActiveCount(),
|
||||
threadPool.getPoolSize(),
|
||||
threadPool.getQueue().size());
|
||||
} catch (Exception e) {
|
||||
LogUtils.error("KAFKA消费失败:", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setThreadPoolSize(int poolSize) {
|
||||
try {
|
||||
if (poolSize > 10 && poolSize < 500 && poolSize != threadPool.getMaximumPoolSize()) {
|
||||
threadPool.setMaximumPoolSize(poolSize);
|
||||
threadPool.setCorePoolSize(poolSize);
|
||||
threadPool.allowCoreThreadTimeOut(true);
|
||||
LogUtils.info("Set successfully: " + threadPool.prestartAllCoreThreads());
|
||||
}
|
||||
LogUtils.info("Invalid thread pool size: " + poolSize);
|
||||
} catch (Exception e) {
|
||||
LogUtils.error("设置线程参数异常", e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -543,7 +543,7 @@ public class ApiDebugControllerTests extends BaseTest {
|
|||
request.setFrontendDebug(true);
|
||||
MvcResult mvcResult = this.requestPostWithOkAndReturn(DEBUG, request);
|
||||
TaskRequestDTO taskRequestDTO = getResultData(mvcResult, TaskRequestDTO.class);
|
||||
Assertions.assertEquals(taskRequestDTO.getReportId(), request.getReportId());
|
||||
Assertions.assertEquals(taskRequestDTO.getTaskItem().getReportId(), request.getReportId());
|
||||
|
||||
// 测试请求体
|
||||
MockMultipartFile file = getMockMultipartFile();
|
||||
|
|
|
@ -67,7 +67,7 @@ public class ApiExecuteResourceControllerTest extends BaseTest {
|
|||
|
||||
String reportId = UUID.randomUUID().toString();
|
||||
String testId = UUID.randomUUID().toString();
|
||||
String scriptRedisKey = apiExecuteService.getScriptRedisKey(reportId, testId);
|
||||
String scriptRedisKey = apiExecuteService.getTaskKey(reportId, testId);
|
||||
stringRedisTemplate.opsForValue().set(scriptRedisKey, "aaa");
|
||||
mockMvc.perform(getPostRequestBuilder(FILE, fileRequest, reportId, testId))
|
||||
.andExpect(status().isOk());
|
||||
|
|
|
@ -166,7 +166,7 @@ public class KubernetesEngineTests extends BaseTest {
|
|||
TaskRequestDTO request = new TaskRequestDTO();
|
||||
ApiRunModeConfigDTO runModeConfig = new ApiRunModeConfigDTO();
|
||||
runModeConfig.setPoolId(id);
|
||||
request.setRunModeConfig(runModeConfig);
|
||||
request.getTaskInfo().setRunModeConfig(runModeConfig);
|
||||
|
||||
final ApiEngine engine = EngineFactory.createApiEngine(request);
|
||||
engine.start();
|
||||
|
|
|
@ -2,6 +2,7 @@ package io.metersphere.system.utils;
|
|||
|
||||
import com.bastiaanjansen.otp.TOTPGenerator;
|
||||
import io.metersphere.sdk.constants.MsHttpHeaders;
|
||||
import io.metersphere.sdk.dto.api.task.TaskBatchRequestDTO;
|
||||
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
|
||||
import io.metersphere.sdk.util.LogUtils;
|
||||
import io.metersphere.system.controller.handler.ResultHolder;
|
||||
|
@ -28,6 +29,7 @@ public class TaskRunnerClient {
|
|||
|
||||
private static final String API_DEBUG = "/api/debug";
|
||||
private static final String API_RUN = "/api/run";
|
||||
private static final String BATCH_API_RUN = "/api/batch/run";
|
||||
private static final String HTTP_BATH = "http://%s:%s";
|
||||
private static final String API_STOP = "/api/stop";
|
||||
|
||||
|
@ -50,6 +52,10 @@ public class TaskRunnerClient {
|
|||
post(endpoint + API_RUN, taskRequest);
|
||||
}
|
||||
|
||||
public static void batchRunApi(String endpoint, TaskBatchRequestDTO taskRequest) throws Exception {
|
||||
post(endpoint + BATCH_API_RUN, taskRequest);
|
||||
}
|
||||
|
||||
public static void stopApi(String endpoint, List<String> reportIds) throws Exception {
|
||||
post(endpoint + API_STOP, reportIds);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue