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;
|
package io.metersphere.sdk.dto.api.task;
|
||||||
|
|
||||||
import io.metersphere.sdk.dto.api.result.MsRegexDTO;
|
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 任务请求参数数据
|
* 任务请求参数数据
|
||||||
|
@ -17,97 +14,15 @@ public class TaskRequestDTO implements Serializable {
|
||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
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
|
@Valid
|
||||||
private ApiRunModeConfigDTO runModeConfig = new ApiRunModeConfigDTO();
|
private TaskInfo taskInfo = new TaskInfo();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO 要执行的请求总量,用于计算执行各种指标
|
* 任务项
|
||||||
*/
|
*/
|
||||||
private Long requestCount;
|
@Valid
|
||||||
|
private TaskItem taskItem;
|
||||||
/**
|
|
||||||
* 记录执行时的环境变量
|
|
||||||
*/
|
|
||||||
private List<String> environmentVariables;
|
|
||||||
|
|
||||||
// TODO 其它执行参数
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
package io.metersphere.api.controller;
|
||||||
|
|
||||||
|
import io.metersphere.api.service.ApiExecuteResourceService;
|
||||||
import io.metersphere.api.service.ApiExecuteService;
|
import io.metersphere.api.service.ApiExecuteService;
|
||||||
import io.metersphere.api.service.definition.ApiReportService;
|
import io.metersphere.sdk.dto.api.task.GetRunScriptRequest;
|
||||||
import io.metersphere.api.service.scenario.ApiScenarioReportService;
|
import io.metersphere.sdk.dto.api.task.GetRunScriptResult;
|
||||||
import io.metersphere.sdk.constants.ExecStatus;
|
|
||||||
import io.metersphere.sdk.file.FileRequest;
|
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.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
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 org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author: jianxing
|
* @Author: jianxing
|
||||||
* @CreateTime: 2023-12-05 17:52
|
* @CreateTime: 2023-12-05 17:52
|
||||||
|
@ -24,15 +19,10 @@ import java.util.Optional;
|
||||||
@RequestMapping("/api/execute/resource")
|
@RequestMapping("/api/execute/resource")
|
||||||
@Tag(name = "接口测试-执行-资源")
|
@Tag(name = "接口测试-执行-资源")
|
||||||
public class ApiExecuteResourceController {
|
public class ApiExecuteResourceController {
|
||||||
|
|
||||||
@Resource
|
|
||||||
private StringRedisTemplate stringRedisTemplate;
|
|
||||||
@Resource
|
@Resource
|
||||||
private ApiExecuteService apiExecuteService;
|
private ApiExecuteService apiExecuteService;
|
||||||
@Resource
|
@Resource
|
||||||
private ApiReportService apiReportService;
|
private ApiExecuteResourceService apiExecuteResourceService;
|
||||||
@Resource
|
|
||||||
private ApiScenarioReportService apiScenarioReportService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取执行脚本
|
* 获取执行脚本
|
||||||
|
@ -44,13 +34,18 @@ public class ApiExecuteResourceController {
|
||||||
@GetMapping("script")
|
@GetMapping("script")
|
||||||
@Operation(summary = "获取执行脚本")
|
@Operation(summary = "获取执行脚本")
|
||||||
public String getScript(@RequestParam("reportId") String reportId, @RequestParam("testId") String testId) {
|
public String getScript(@RequestParam("reportId") String reportId, @RequestParam("testId") String testId) {
|
||||||
String key = apiExecuteService.getScriptRedisKey(reportId, testId);
|
return apiExecuteResourceService.getRunScript(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
|
||||||
|
*/
|
||||||
|
@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.ApiValidateService;
|
||||||
import io.metersphere.api.service.scenario.ApiScenarioLogService;
|
import io.metersphere.api.service.scenario.ApiScenarioLogService;
|
||||||
import io.metersphere.api.service.scenario.ApiScenarioNoticeService;
|
import io.metersphere.api.service.scenario.ApiScenarioNoticeService;
|
||||||
|
import io.metersphere.api.service.scenario.ApiScenarioRunService;
|
||||||
import io.metersphere.api.service.scenario.ApiScenarioService;
|
import io.metersphere.api.service.scenario.ApiScenarioService;
|
||||||
import io.metersphere.project.service.FileModuleService;
|
import io.metersphere.project.service.FileModuleService;
|
||||||
import io.metersphere.sdk.constants.PermissionConstants;
|
import io.metersphere.sdk.constants.PermissionConstants;
|
||||||
|
@ -49,6 +50,8 @@ public class ApiScenarioController {
|
||||||
@Resource
|
@Resource
|
||||||
private ApiScenarioService apiScenarioService;
|
private ApiScenarioService apiScenarioService;
|
||||||
@Resource
|
@Resource
|
||||||
|
private ApiScenarioRunService apiScenarioRunService;
|
||||||
|
@Resource
|
||||||
private ApiValidateService apiValidateService;
|
private ApiValidateService apiValidateService;
|
||||||
@Resource
|
@Resource
|
||||||
private FileModuleService fileModuleService;
|
private FileModuleService fileModuleService;
|
||||||
|
@ -166,14 +169,14 @@ public class ApiScenarioController {
|
||||||
@Operation(summary = "接口测试-接口场景管理-场景调试")
|
@Operation(summary = "接口测试-接口场景管理-场景调试")
|
||||||
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_EXECUTE)
|
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_EXECUTE)
|
||||||
public TaskRequestDTO debug(@Validated @RequestBody ApiScenarioDebugRequest request) {
|
public TaskRequestDTO debug(@Validated @RequestBody ApiScenarioDebugRequest request) {
|
||||||
return apiScenarioService.debug(request);
|
return apiScenarioRunService.debug(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/run")
|
@PostMapping("/run")
|
||||||
@Operation(summary = "接口测试-接口场景管理-场景执行")
|
@Operation(summary = "接口测试-接口场景管理-场景执行")
|
||||||
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_EXECUTE)
|
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_EXECUTE)
|
||||||
public TaskRequestDTO run(@Validated @RequestBody ApiScenarioDebugRequest request) {
|
public TaskRequestDTO run(@Validated @RequestBody ApiScenarioDebugRequest request) {
|
||||||
return apiScenarioService.run(request, SessionUtils.getUserId());
|
return apiScenarioRunService.run(request, SessionUtils.getUserId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/run/{id}")
|
@GetMapping("/run/{id}")
|
||||||
|
@ -181,7 +184,7 @@ public class ApiScenarioController {
|
||||||
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_EXECUTE)
|
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_EXECUTE)
|
||||||
@CheckOwner(resourceId = "#id", resourceType = "api_scenario")
|
@CheckOwner(resourceId = "#id", resourceType = "api_scenario")
|
||||||
public TaskRequestDTO run(@PathVariable String id, @RequestParam(required = false) String reportId) {
|
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}")
|
@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.ApiScenarioDetail;
|
||||||
import io.metersphere.api.dto.scenario.ApiScenarioParseParam;
|
import io.metersphere.api.dto.scenario.ApiScenarioParseParam;
|
||||||
import io.metersphere.api.service.ApiExecuteService;
|
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.ApiBatchRunMode;
|
||||||
import io.metersphere.sdk.constants.ApiExecuteRunMode;
|
import io.metersphere.sdk.constants.ApiExecuteRunMode;
|
||||||
import io.metersphere.sdk.constants.TaskTriggerMode;
|
import io.metersphere.sdk.constants.TaskTriggerMode;
|
||||||
import io.metersphere.sdk.dto.api.task.ApiRunModeConfigDTO;
|
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.dto.api.task.TaskRequestDTO;
|
||||||
import io.metersphere.sdk.util.CommonBeanFactory;
|
import io.metersphere.sdk.util.CommonBeanFactory;
|
||||||
import io.metersphere.sdk.util.JSON;
|
import io.metersphere.sdk.util.JSON;
|
||||||
|
@ -27,17 +29,17 @@ import org.quartz.TriggerKey;
|
||||||
public class ApiScenarioScheduleJob extends BaseScheduleJob {
|
public class ApiScenarioScheduleJob extends BaseScheduleJob {
|
||||||
@Override
|
@Override
|
||||||
protected void businessExecute(JobExecutionContext context) {
|
protected void businessExecute(JobExecutionContext context) {
|
||||||
ApiScenarioService apiScenarioService = CommonBeanFactory.getBean(ApiScenarioService.class);
|
|
||||||
ApiExecuteService apiExecuteService = CommonBeanFactory.getBean(ApiExecuteService.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);
|
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) {
|
if (apiScenarioDetail == null) {
|
||||||
LogUtils.info("当前定时任务的场景已删除 {}", resourceId);
|
LogUtils.info("当前定时任务的场景已删除 {}", resourceId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MsScenario msScenario = apiScenarioService.getMsScenario(apiScenarioDetail);
|
MsScenario msScenario = apiScenarioRunService.getMsScenario(apiScenarioDetail);
|
||||||
ApiScenarioParseParam parseParam = apiScenarioService.getApiScenarioParseParam(apiScenarioDetail);
|
ApiScenarioParseParam parseParam = apiScenarioRunService.getApiScenarioParseParam(apiScenarioDetail);
|
||||||
parseParam.setEnvironmentId(apiRunModeConfigDTO.getEnvironmentId());
|
parseParam.setEnvironmentId(apiRunModeConfigDTO.getEnvironmentId());
|
||||||
parseParam.setGrouped(apiRunModeConfigDTO.getGrouped());
|
parseParam.setGrouped(apiRunModeConfigDTO.getGrouped());
|
||||||
|
|
||||||
|
@ -52,33 +54,35 @@ public class ApiScenarioScheduleJob extends BaseScheduleJob {
|
||||||
|
|
||||||
msScenario.setResourceId(apiScenarioDetail.getId());
|
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());
|
TaskRequestDTO taskRequest = apiScenarioRunService.getTaskRequest(IDGenerator.nextStr(), apiScenarioDetail.getId(), apiScenarioDetail.getProjectId(), ApiExecuteRunMode.SCENARIO.name());
|
||||||
taskRequest.getRunModeConfig().setPoolId(apiRunModeConfigDTO.getPoolId());
|
TaskInfo taskInfo = taskRequest.getTaskInfo();
|
||||||
taskRequest.setSaveResult(true);
|
TaskItem taskItem = taskRequest.getTaskItem();
|
||||||
taskRequest.setRealTime(false);
|
taskInfo.getRunModeConfig().setPoolId(apiRunModeConfigDTO.getPoolId());
|
||||||
taskRequest.getRunModeConfig().setEnvironmentId(parseParam.getEnvironmentId());
|
taskInfo.setSaveResult(true);
|
||||||
taskRequest.setRequestCount(tmpParam.getRequestCount().get());
|
taskInfo.setRealTime(false);
|
||||||
|
taskInfo.getRunModeConfig().setEnvironmentId(parseParam.getEnvironmentId());
|
||||||
|
taskItem.setRequestCount(tmpParam.getRequestCount().get());
|
||||||
|
|
||||||
ApiScenarioParamConfig parseConfig = apiScenarioService.getApiScenarioParamConfig(parseParam, tmpParam.getScenarioParseEnvInfo());
|
ApiScenarioParamConfig parseConfig = apiScenarioRunService.getApiScenarioParamConfig(msScenario.getProjectId(), parseParam, tmpParam.getScenarioParseEnvInfo());
|
||||||
parseConfig.setReportId(taskRequest.getReportId());
|
parseConfig.setReportId(taskItem.getReportId());
|
||||||
|
|
||||||
// 初始化报告
|
// 初始化报告
|
||||||
ApiScenarioReport scenarioReport = apiScenarioService.getScenarioReport(userId);
|
ApiScenarioReport scenarioReport = apiScenarioRunService.getScenarioReport(userId);
|
||||||
scenarioReport.setId(taskRequest.getReportId());
|
scenarioReport.setId(taskItem.getReportId());
|
||||||
scenarioReport.setTriggerMode(TaskTriggerMode.SCHEDULE.name());
|
scenarioReport.setTriggerMode(TaskTriggerMode.SCHEDULE.name());
|
||||||
scenarioReport.setRunMode(ApiBatchRunMode.PARALLEL.name());
|
scenarioReport.setRunMode(ApiBatchRunMode.PARALLEL.name());
|
||||||
scenarioReport.setPoolId(apiRunModeConfigDTO.getPoolId());
|
scenarioReport.setPoolId(apiRunModeConfigDTO.getPoolId());
|
||||||
scenarioReport.setEnvironmentId(parseParam.getEnvironmentId());
|
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);
|
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.dto.environment.GlobalParamsDTO;
|
||||||
import io.metersphere.project.service.*;
|
import io.metersphere.project.service.*;
|
||||||
import io.metersphere.sdk.constants.*;
|
import io.metersphere.sdk.constants.*;
|
||||||
import io.metersphere.sdk.dto.api.task.ApiExecuteFileInfo;
|
import io.metersphere.sdk.dto.api.task.*;
|
||||||
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.exception.MSException;
|
||||||
import io.metersphere.sdk.exception.TaskRunnerResultCode;
|
import io.metersphere.sdk.exception.TaskRunnerResultCode;
|
||||||
import io.metersphere.sdk.file.FileCenter;
|
import io.metersphere.sdk.file.FileCenter;
|
||||||
|
@ -56,6 +54,7 @@ import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Collectors;
|
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;
|
return reportId + "_" + testId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TaskRequestDTO execute(ApiResourceRunRequest runRequest, TaskRequestDTO taskRequest, ApiParamConfig parameterConfig) {
|
public TaskRequestDTO execute(ApiResourceRunRequest runRequest, TaskRequestDTO taskRequest, ApiParamConfig parameterConfig) {
|
||||||
// 置minio kafka ms 等信息
|
TaskInfo taskInfo = taskRequest.getTaskInfo();
|
||||||
setServerInfoParam(taskRequest);
|
TaskItem taskItem = taskRequest.getTaskItem();
|
||||||
|
|
||||||
// 设置执行文件参数
|
|
||||||
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()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 解析执行脚本
|
// 解析执行脚本
|
||||||
String executeScript = parseExecuteScript(runRequest.getTestElement(), parameterConfig);
|
String executeScript = parseExecuteScript(runRequest.getTestElement(), parameterConfig);
|
||||||
|
// 脚本已经解析,不需要再解析
|
||||||
// 设置插件文件信息 todo 多项目
|
taskInfo.setNeedParseScript(false);
|
||||||
List<ApiExecuteFileInfo> pluginFiles = new ArrayList<>();
|
|
||||||
pluginFiles.addAll(apiPluginService.getFileInfoByProjectId(taskRequest.getProjectId()));
|
|
||||||
pluginFiles.addAll(jdbcDriverPluginService.getFileInfoByProjectId(taskRequest.getProjectId()));
|
|
||||||
|
|
||||||
taskRequest.setPluginFiles(pluginFiles);
|
|
||||||
|
|
||||||
// 将测试脚本缓存到 redis
|
// 将测试脚本缓存到 redis
|
||||||
String scriptRedisKey = getScriptRedisKey(taskRequest.getReportId(), taskRequest.getResourceId());
|
String scriptRedisKey = getTaskKey(taskItem.getReportId(), taskItem.getResourceId());
|
||||||
stringRedisTemplate.opsForValue().set(scriptRedisKey, executeScript, 1, TimeUnit.DAYS);
|
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配置信息,避免前端获取
|
// 清空mino和kafka配置信息,避免前端获取
|
||||||
taskRequest.setMinioConfig(null);
|
taskInfo.setMinioConfig(null);
|
||||||
taskRequest.setKafkaConfig(null);
|
taskInfo.setKafkaConfig(null);
|
||||||
// 前端调试返回执行参数,由前端调用本地资源池执行
|
// 前端调试返回执行参数,由前端调用本地资源池执行
|
||||||
return taskRequest;
|
return taskRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return doExecute(taskRequest);
|
return execute(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;
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
handleDoExecuteException(scriptRedisKey, e);
|
// 调用失败清理脚本
|
||||||
// 集合报告对应的资源池集合移除
|
stringRedisTemplate.delete(scriptRedisKey);
|
||||||
removeCollectionReport(taskRequest);
|
throw e;
|
||||||
throw new MSException(RESOURCE_POOL_EXECUTE_ERROR, e.getMessage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleDoExecuteException(String scriptRedisKey, Exception e) {
|
private TaskInfo setTaskRequestParams(TaskInfo taskInfo) {
|
||||||
LogUtils.error(e);
|
// 置minio kafka ms 等信息
|
||||||
// 调用失败清理脚本
|
setServerInfoParam(taskInfo);
|
||||||
stringRedisTemplate.delete(scriptRedisKey);
|
// 设置项目执行所需要的文件信息
|
||||||
|
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) {
|
private void setProjectPluginParam(TaskInfo taskInfo) {
|
||||||
// 集合报告对应的资源池集合移除
|
// 设置插件文件信息
|
||||||
if (taskRequest.getRunModeConfig().getIntegratedReport()) {
|
CopyOnWriteArrayList<ApiExecuteFileInfo> pluginFiles = new CopyOnWriteArrayList<>();
|
||||||
String SET_PREFIX = "set:" + taskRequest.getRunModeConfig().getCollectionReport().getReportId();
|
pluginFiles.addAll(apiPluginService.getFileInfoByProjectId(taskInfo.getProjectId()));
|
||||||
stringRedisTemplate.opsForSet().remove(SET_PREFIX, taskRequest.getResourceId());
|
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);
|
GlobalParamsDTO globalParamsDTO = globalParamsService.get(projectId);
|
||||||
if (globalParamsDTO != null) {
|
if (globalParamsDTO != null) {
|
||||||
return globalParamsDTO.getGlobalParams();
|
return globalParamsDTO.getGlobalParams();
|
||||||
|
@ -214,37 +201,110 @@ public class ApiExecuteService {
|
||||||
*
|
*
|
||||||
* @param taskRequest 执行参数
|
* @param taskRequest 执行参数
|
||||||
*/
|
*/
|
||||||
private TaskRequestDTO doExecute(TaskRequestDTO taskRequest) throws Exception {
|
public TaskRequestDTO execute(TaskRequestDTO taskRequest) {
|
||||||
// 获取资源池
|
TaskInfo taskInfo = taskRequest.getTaskInfo();
|
||||||
TestResourcePoolReturnDTO testResourcePoolDTO = getGetResourcePoolNodeDTO(taskRequest.getRunModeConfig(), taskRequest.getProjectId());
|
TaskItem taskItem = taskRequest.getTaskItem();
|
||||||
if (testResourcePoolDTO == null || CollectionUtils.isEmpty(testResourcePoolDTO.getTestResourceReturnDTO().getNodesList())) {
|
|
||||||
throw new MSException(ApiResultCode.EXECUTE_RESOURCE_POOL_NOT_CONFIG);
|
|
||||||
}
|
|
||||||
TestResourceNodeDTO testResourceNodeDTO = getProjectExecuteNode(testResourcePoolDTO);
|
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(testResourcePoolDTO.getServerUrl())) {
|
try {
|
||||||
// 如果资源池配置了当前站点,则使用资源池的
|
|
||||||
taskRequest.setMsUrl(testResourcePoolDTO.getServerUrl());
|
|
||||||
}
|
|
||||||
taskRequest.setPoolSize(testResourceNodeDTO.getConcurrentNumber());
|
|
||||||
|
|
||||||
String endpoint = TaskRunnerClient.getEndpoint(testResourceNodeDTO.getIp(), testResourceNodeDTO.getPort());
|
taskInfo = setTaskRequestParams(taskInfo);
|
||||||
LogUtils.info("开始发送请求【 {}_{} 】到 {} 节点执行", taskRequest.getReportId(), taskRequest.getResourceId(), endpoint);
|
|
||||||
if (StringUtils.equalsAny(taskRequest.getRunMode(), ApiExecuteRunMode.FRONTEND_DEBUG.name(), ApiExecuteRunMode.BACKEND_DEBUG.name())) {
|
// 获取资源池
|
||||||
TaskRunnerClient.debugApi(endpoint, taskRequest);
|
TestResourcePoolReturnDTO testResourcePoolDTO = getGetResourcePoolNodeDTO(taskInfo.getRunModeConfig(), taskInfo.getProjectId());
|
||||||
} else {
|
|
||||||
TaskRunnerClient.runApi(endpoint, taskRequest);
|
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配置信息,避免前端获取
|
// 清空mino和kafka配置信息,避免前端获取
|
||||||
taskRequest.setMinioConfig(null);
|
taskInfo.setMinioConfig(null);
|
||||||
taskRequest.setKafkaConfig(null);
|
taskInfo.setKafkaConfig(null);
|
||||||
|
|
||||||
return taskRequest;
|
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());
|
roundRobinService.initializeNodes(resourcePoolDTO.getId(), resourcePoolDTO.getTestResourceReturnDTO().getNodesList());
|
||||||
try {
|
try {
|
||||||
TestResourceNodeDTO node = roundRobinService.getNextNode(resourcePoolDTO.getId());
|
TestResourceNodeDTO node = roundRobinService.getNextNode(resourcePoolDTO.getId());
|
||||||
|
@ -263,18 +323,23 @@ public class ApiExecuteService {
|
||||||
if (StringUtils.isBlank(poolId)) {
|
if (StringUtils.isBlank(poolId)) {
|
||||||
poolId = getProjectApiResourcePoolId(projectId);
|
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 等信息
|
* 设置minio kafka ms 等信息
|
||||||
*
|
*
|
||||||
* @param taskRequest 执行参数
|
* @param taskInfo 执行参数
|
||||||
*/
|
*/
|
||||||
private void setServerInfoParam(TaskRequestDTO taskRequest) {
|
private void setServerInfoParam(TaskInfo taskInfo) {
|
||||||
taskRequest.setKafkaConfig(EncryptUtils.aesEncrypt(JSON.toJSONString(KafkaConfig.getKafkaConfig())));
|
taskInfo.setKafkaConfig(EncryptUtils.aesEncrypt(JSON.toJSONString(KafkaConfig.getKafkaConfig())));
|
||||||
taskRequest.setMinioConfig(EncryptUtils.aesEncrypt(JSON.toJSONString(getMinio())));
|
taskInfo.setMinioConfig(EncryptUtils.aesEncrypt(JSON.toJSONString(getMinio())));
|
||||||
taskRequest.setMsUrl(systemParameterService.getBaseInfo().getUrl());
|
taskInfo.setMsUrl(systemParameterService.getBaseInfo().getUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -305,11 +370,12 @@ public class ApiExecuteService {
|
||||||
|
|
||||||
// 设置执行参数
|
// 设置执行参数
|
||||||
TaskRequestDTO taskRequest = getTaskRequest(reportId, testId, runRequest.getProjectId());
|
TaskRequestDTO taskRequest = getTaskRequest(reportId, testId, runRequest.getProjectId());
|
||||||
setServerInfoParam(taskRequest);
|
TaskInfo taskInfo = taskRequest.getTaskInfo();
|
||||||
taskRequest.setRealTime(true);
|
setServerInfoParam(taskInfo);
|
||||||
taskRequest.setSaveResult(false);
|
taskInfo.setRealTime(true);
|
||||||
taskRequest.setResourceType(ApiExecuteResourceType.API_DEBUG.name());
|
taskInfo.setSaveResult(false);
|
||||||
taskRequest.setRunMode(ApiExecuteRunMode.BACKEND_DEBUG.name());
|
taskInfo.setResourceType(ApiExecuteResourceType.API_DEBUG.name());
|
||||||
|
taskInfo.setRunMode(ApiExecuteRunMode.BACKEND_DEBUG.name());
|
||||||
|
|
||||||
return execute(apiRunRequest, taskRequest, new ApiParamConfig());
|
return execute(apiRunRequest, taskRequest, new ApiParamConfig());
|
||||||
}
|
}
|
||||||
|
@ -318,57 +384,77 @@ public class ApiExecuteService {
|
||||||
* 给 taskRequest 设置文件相关参数
|
* 给 taskRequest 设置文件相关参数
|
||||||
*
|
*
|
||||||
* @param runRequest 请求参数
|
* @param runRequest 请求参数
|
||||||
* @param taskRequest 执行参数
|
|
||||||
*/
|
*/
|
||||||
private void setTaskFileParam(ApiResourceRunRequest runRequest, TaskRequestDTO taskRequest) {
|
public void setTaskItemFileParam(ApiResourceRunRequest runRequest, TaskItem taskItem) {
|
||||||
setTaskRefFileParam(runRequest, taskRequest);
|
// 接口执行相关的文件
|
||||||
setTaskTmpFileParam(runRequest, taskRequest);
|
setTaskRefFileParam(runRequest, taskItem.getTaskResourceFile(), taskItem.getResourceId());
|
||||||
setTaskFuncJarParam(runRequest, taskRequest);
|
// 调试时未保存的文件
|
||||||
|
setTaskTmpFileParam(runRequest, taskItem.getTaskResourceFile());
|
||||||
|
// 场景引用跨项目的用例所需要的jar包
|
||||||
|
setTaskFuncJarParam(taskItem, runRequest.getRefProjectIds().stream().toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 给 taskRequest 设置文件相关参数
|
||||||
|
*/
|
||||||
|
public void setTaskItemFileParam(TaskItem taskItem) {
|
||||||
|
setTaskItemFileParam(new ApiResourceRunRequest(), taskItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理脚本执行所需要的jar包
|
* 处理脚本执行所需要的jar包
|
||||||
*
|
*
|
||||||
* @param runRequest
|
* @param taskInfo
|
||||||
* @param taskRequest
|
|
||||||
*/
|
*/
|
||||||
private void setTaskFuncJarParam(ApiResourceRunRequest runRequest, TaskRequestDTO taskRequest) {
|
private void setTaskFuncJarParam(TaskInfo taskInfo) {
|
||||||
Set<String> projectIdsSet = runRequest.getRefProjectIds();
|
|
||||||
projectIdsSet.add(taskRequest.getProjectId());
|
|
||||||
List<String> projectIds = projectIdsSet.stream().collect(Collectors.toList());
|
|
||||||
|
|
||||||
// 获取函数jar包
|
// 获取函数jar包
|
||||||
List<FileMetadata> fileMetadataList = fileManagementService.findJarByProjectId(projectIds);
|
List<FileMetadata> fileMetadataList = fileManagementService.findJarByProjectId(List.of(taskInfo.getProjectId()));
|
||||||
taskRequest.setFuncJars(getApiExecuteFileInfo(fileMetadataList));
|
taskInfo.getProjectResource().setFuncJars(getApiExecuteFileInfo(fileMetadataList));
|
||||||
|
|
||||||
// TODO 当前项目没有包分两种情况,1 之前存在被删除,2 一直不存在
|
// TODO 当前项目没有包分两种情况,1 之前存在被删除,2 一直不存在
|
||||||
// 为了兼容1 这种情况需要初始化一条空的数据,由执行机去做卸载
|
// 为了兼容1 这种情况需要初始化一条空的数据,由执行机去做卸载
|
||||||
if (CollectionUtils.isEmpty(taskRequest.getFuncJars())) {
|
if (CollectionUtils.isEmpty(taskInfo.getProjectResource().getFuncJars())) {
|
||||||
ApiExecuteFileInfo tempFileInfo = new ApiExecuteFileInfo();
|
ApiExecuteFileInfo tempFileInfo = new ApiExecuteFileInfo();
|
||||||
tempFileInfo.setProjectId(taskRequest.getProjectId());
|
tempFileInfo.setProjectId(taskInfo.getProjectId());
|
||||||
taskRequest.setFuncJars(List.of(tempFileInfo));
|
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 runRequest
|
||||||
* @param taskRequest
|
|
||||||
*/
|
*/
|
||||||
private void setTaskTmpFileParam(ApiResourceRunRequest runRequest, TaskRequestDTO taskRequest) {
|
private void setTaskTmpFileParam(ApiResourceRunRequest runRequest, TaskResourceFile taskResourceFile) {
|
||||||
// 没有保存的本地临时文件
|
// 没有保存的本地临时文件
|
||||||
List<String> uploadFileIds = runRequest.getUploadFileIds();
|
List<String> uploadFileIds = runRequest.getUploadFileIds();
|
||||||
if (CollectionUtils.isNotEmpty(uploadFileIds)) {
|
if (CollectionUtils.isNotEmpty(uploadFileIds)) {
|
||||||
List<ApiExecuteFileInfo> localTempFiles = uploadFileIds.stream()
|
List<ApiExecuteFileInfo> localTempFiles = uploadFileIds.stream()
|
||||||
.map(tempFileId -> {
|
.map(tempFileId -> {
|
||||||
String fileName = apiFileResourceService.getTempFileNameByFileId(tempFileId);
|
String fileName = apiFileResourceService.getTempFileNameByFileId(tempFileId);
|
||||||
return getApiExecuteFileInfo(tempFileId, fileName, taskRequest.getProjectId());
|
return getApiExecuteFileInfo(tempFileId, fileName, null);
|
||||||
})
|
})
|
||||||
// uploadFileIds 查不到,则已经移动到正式目录
|
// uploadFileIds 查不到,则已经移动到正式目录
|
||||||
.filter(i -> StringUtils.isNotBlank(i.getFileName()))
|
.filter(i -> StringUtils.isNotBlank(i.getFileName()))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
taskRequest.setLocalTempFiles(localTempFiles);
|
taskResourceFile.setLocalTempFiles(localTempFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> linkFileIds = runRequest.getLinkFileIds();
|
List<String> linkFileIds = runRequest.getLinkFileIds();
|
||||||
|
@ -376,7 +462,7 @@ public class ApiExecuteService {
|
||||||
if (CollectionUtils.isNotEmpty(linkFileIds)) {
|
if (CollectionUtils.isNotEmpty(linkFileIds)) {
|
||||||
List<FileMetadata> fileMetadataList = fileMetadataService.getByFileIds(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 runRequest
|
||||||
* @param taskRequest
|
|
||||||
*/
|
*/
|
||||||
private void setTaskRefFileParam(ApiResourceRunRequest runRequest, TaskRequestDTO taskRequest) {
|
private void setTaskRefFileParam(ApiResourceRunRequest runRequest, TaskResourceFile taskResourceFile, String resourceId) {
|
||||||
// 查询包括资源所需的文件
|
// 查询包括资源所需的文件
|
||||||
Set<String> resourceIdsSet = runRequest.getFileResourceIds();
|
Set<String> resourceIdsSet = runRequest.getFileResourceIds();
|
||||||
resourceIdsSet.add(taskRequest.getResourceId());
|
resourceIdsSet.add(resourceId);
|
||||||
List<String> resourceIds = resourceIdsSet.stream().collect(Collectors.toList());
|
List<String> resourceIds = resourceIdsSet.stream().collect(Collectors.toList());
|
||||||
SubListUtils.dealForSubList(resourceIds, 50, subResourceIds -> {
|
SubListUtils.dealForSubList(resourceIds, 50, subResourceIds -> {
|
||||||
// 查询通过本地上传的文件
|
// 查询通过本地上传的文件
|
||||||
|
@ -406,7 +491,7 @@ public class ApiExecuteService {
|
||||||
return apiExecuteFileInfo;
|
return apiExecuteFileInfo;
|
||||||
})
|
})
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
taskRequest.setLocalFiles(localFiles);
|
taskResourceFile.setLocalFiles(localFiles);
|
||||||
|
|
||||||
// 查询关联的文件管理的文件
|
// 查询关联的文件管理的文件
|
||||||
List<ApiExecuteFileInfo> refFiles = fileAssociationService.getFiles(subResourceIds).
|
List<ApiExecuteFileInfo> refFiles = fileAssociationService.getFiles(subResourceIds).
|
||||||
|
@ -421,11 +506,11 @@ public class ApiExecuteService {
|
||||||
}
|
}
|
||||||
return refFileInfo;
|
return refFileInfo;
|
||||||
}).collect(Collectors.toList());
|
}).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()
|
return fileMetadataList.stream()
|
||||||
.map(file -> {
|
.map(file -> {
|
||||||
ApiExecuteFileInfo tempFileInfo = getApiExecuteFileInfo(file.getId(), file.getOriginalName(),
|
ApiExecuteFileInfo tempFileInfo = getApiExecuteFileInfo(file.getId(), file.getOriginalName(),
|
||||||
|
@ -436,7 +521,7 @@ public class ApiExecuteService {
|
||||||
tempFileInfo.setFileModuleRepositoryDTO(fileManagementService.getFileModuleRepositoryDTO(file.getModuleId()));
|
tempFileInfo.setFileModuleRepositoryDTO(fileManagementService.getFileModuleRepositoryDTO(file.getModuleId()));
|
||||||
}
|
}
|
||||||
return tempFileInfo;
|
return tempFileInfo;
|
||||||
}).toList();
|
}).collect(Collectors.toCollection(CopyOnWriteArrayList::new));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ApiExecuteFileInfo getApiExecuteFileInfo(String fileId, String fileName, String projectId) {
|
private ApiExecuteFileInfo getApiExecuteFileInfo(String fileId, String fileName, String projectId) {
|
||||||
|
@ -459,7 +544,7 @@ public class ApiExecuteService {
|
||||||
* @param config 参数配置
|
* @param config 参数配置
|
||||||
* @return 执行脚本
|
* @return 执行脚本
|
||||||
*/
|
*/
|
||||||
private String parseExecuteScript(AbstractMsTestElement msTestElement, ParameterConfig config) {
|
public String parseExecuteScript(AbstractMsTestElement msTestElement, ParameterConfig config) {
|
||||||
// 解析生成脚本
|
// 解析生成脚本
|
||||||
TestElementParser defaultParser = TestElementParserFactory.getDefaultParser();
|
TestElementParser defaultParser = TestElementParserFactory.getDefaultParser();
|
||||||
return defaultParser.parse(msTestElement, config);
|
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 {
|
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))) {
|
if (BooleanUtils.isTrue(stringRedisTemplate.hasKey(key))) {
|
||||||
FileRepository repository = StringUtils.isBlank(fileRequest.getStorage()) ? FileCenter.getDefaultRepository()
|
FileRepository repository = StringUtils.isBlank(fileRequest.getStorage()) ? FileCenter.getDefaultRepository()
|
||||||
: FileCenter.getRepository(fileRequest.getStorage());
|
: FileCenter.getRepository(fileRequest.getStorage());
|
||||||
|
@ -546,14 +631,17 @@ public class ApiExecuteService {
|
||||||
*/
|
*/
|
||||||
public TaskRequestDTO apiExecute(ApiResourceRunRequest runRequest, TaskRequestDTO taskRequest, ApiParamConfig apiParamConfig) {
|
public TaskRequestDTO apiExecute(ApiResourceRunRequest runRequest, TaskRequestDTO taskRequest, ApiParamConfig apiParamConfig) {
|
||||||
// 设置使用脚本前后置的公共脚本信息
|
// 设置使用脚本前后置的公共脚本信息
|
||||||
AbstractMsTestElement testElement = runRequest.getTestElement();
|
setTestElementParam(runRequest.getTestElement(), taskRequest.getTaskInfo().getProjectId(), taskRequest.getTaskItem());
|
||||||
apiCommonService.setEnableCommonScriptProcessorInfo(testElement);
|
|
||||||
testElement.setResourceId(taskRequest.getResourceId());
|
|
||||||
testElement.setStepId(taskRequest.getResourceId());
|
|
||||||
testElement.setProjectId(taskRequest.getProjectId());
|
|
||||||
return execute(runRequest, taskRequest, apiParamConfig);
|
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) {
|
public ApiParamConfig getApiParamConfig(String reportId) {
|
||||||
ApiParamConfig paramConfig = new ApiParamConfig();
|
ApiParamConfig paramConfig = new ApiParamConfig();
|
||||||
paramConfig.setTestElementClassPluginIdMap(apiPluginService.getTestElementPluginMap());
|
paramConfig.setTestElementClassPluginIdMap(apiPluginService.getTestElementPluginMap());
|
||||||
|
@ -562,14 +650,37 @@ public class ApiExecuteService {
|
||||||
return paramConfig;
|
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) {
|
public TaskRequestDTO getTaskRequest(String reportId, String resourceId, String projectId) {
|
||||||
TaskRequestDTO taskRequest = new TaskRequestDTO();
|
TaskRequestDTO taskRequest = new TaskRequestDTO();
|
||||||
taskRequest.setReportId(reportId);
|
TaskInfo taskInfo = getTaskInfo(projectId);
|
||||||
taskRequest.setResourceId(resourceId);
|
TaskItem taskItem = getTaskItem(reportId, resourceId);
|
||||||
taskRequest.setProjectId(projectId);
|
taskRequest.setTaskInfo(taskInfo);
|
||||||
|
taskRequest.setTaskItem(taskItem);
|
||||||
return taskRequest;
|
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) {
|
public String getDebugRunModule(boolean isFrontendDebug) {
|
||||||
return isFrontendDebug ? ApiExecuteRunMode.FRONTEND_DEBUG.name() : ApiExecuteRunMode.BACKEND_DEBUG.name();
|
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.constants.*;
|
||||||
import io.metersphere.sdk.dto.api.result.ProcessResultDTO;
|
import io.metersphere.sdk.dto.api.result.ProcessResultDTO;
|
||||||
import io.metersphere.sdk.dto.api.result.TaskResultDTO;
|
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.dto.api.task.TaskRequestDTO;
|
||||||
import io.metersphere.sdk.exception.MSException;
|
import io.metersphere.sdk.exception.MSException;
|
||||||
import io.metersphere.sdk.util.*;
|
import io.metersphere.sdk.util.*;
|
||||||
|
@ -293,11 +295,14 @@ public class ApiTaskCenterService {
|
||||||
LogUtils.error(e);
|
LogUtils.error(e);
|
||||||
} finally {
|
} finally {
|
||||||
subList.forEach(reportId -> {
|
subList.forEach(reportId -> {
|
||||||
taskRequestDTO.setReportId(reportId);
|
TaskInfo taskInfo = taskRequestDTO.getTaskInfo();
|
||||||
taskRequestDTO.setResourceType(request.getModuleType());
|
TaskItem taskItem = new TaskItem();
|
||||||
taskRequestDTO.getRunModeConfig().setIntegratedReport(integrationMap.get(reportId));
|
taskRequestDTO.setTaskItem(taskItem);
|
||||||
|
taskItem.setReportId(reportId);
|
||||||
|
taskInfo.setResourceType(request.getModuleType());
|
||||||
|
taskInfo.getRunModeConfig().setIntegratedReport(integrationMap.get(reportId));
|
||||||
if (BooleanUtils.isTrue(integrationMap.get(reportId))) {
|
if (BooleanUtils.isTrue(integrationMap.get(reportId))) {
|
||||||
taskRequestDTO.getRunModeConfig().getCollectionReport().setReportId(reportId);
|
taskInfo.getRunModeConfig().getCollectionReport().setReportId(reportId);
|
||||||
}
|
}
|
||||||
result.setRequest(taskRequestDTO);
|
result.setRequest(taskRequestDTO);
|
||||||
kafkaTemplate.send(KafkaTopicConstants.API_REPORT_TOPIC, JSON.toJSONString(result));
|
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.project.service.ProjectService;
|
||||||
import io.metersphere.sdk.constants.ApiFileResourceType;
|
import io.metersphere.sdk.constants.ApiFileResourceType;
|
||||||
import io.metersphere.sdk.constants.DefaultRepositoryDir;
|
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.dto.api.task.TaskRequestDTO;
|
||||||
import io.metersphere.sdk.exception.MSException;
|
import io.metersphere.sdk.exception.MSException;
|
||||||
import io.metersphere.sdk.util.BeanUtils;
|
import io.metersphere.sdk.util.BeanUtils;
|
||||||
|
@ -213,10 +214,11 @@ public class ApiDebugService extends MoveNodeService {
|
||||||
ApiParamConfig apiParamConfig = apiExecuteService.getApiParamConfig(request.getReportId());
|
ApiParamConfig apiParamConfig = apiExecuteService.getApiParamConfig(request.getReportId());
|
||||||
|
|
||||||
TaskRequestDTO taskRequest = apiExecuteService.getTaskRequest(request.getReportId(), request.getId(), request.getProjectId());
|
TaskRequestDTO taskRequest = apiExecuteService.getTaskRequest(request.getReportId(), request.getId(), request.getProjectId());
|
||||||
taskRequest.setSaveResult(false);
|
TaskInfo taskInfo = taskRequest.getTaskInfo();
|
||||||
taskRequest.setRealTime(true);
|
taskInfo.setSaveResult(false);
|
||||||
taskRequest.setResourceType(ApiResourceType.API_DEBUG.name());
|
taskInfo.setRealTime(true);
|
||||||
taskRequest.setRunMode(apiExecuteService.getDebugRunModule(request.getFrontendDebug()));
|
taskInfo.setResourceType(ApiResourceType.API_DEBUG.name());
|
||||||
|
taskInfo.setRunMode(apiExecuteService.getDebugRunModule(request.getFrontendDebug()));
|
||||||
return apiExecuteService.apiExecute(runRequest, taskRequest, apiParamConfig);
|
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.DefaultRepositoryDir;
|
||||||
import io.metersphere.sdk.constants.ModuleConstants;
|
import io.metersphere.sdk.constants.ModuleConstants;
|
||||||
import io.metersphere.sdk.domain.OperationLogBlob;
|
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.dto.api.task.TaskRequestDTO;
|
||||||
import io.metersphere.sdk.exception.MSException;
|
import io.metersphere.sdk.exception.MSException;
|
||||||
import io.metersphere.sdk.mapper.OperationLogBlobMapper;
|
import io.metersphere.sdk.mapper.OperationLogBlobMapper;
|
||||||
|
@ -1145,13 +1146,14 @@ public class ApiDefinitionService extends MoveNodeService {
|
||||||
public TaskRequestDTO debug(ApiDefinitionRunRequest request) {
|
public TaskRequestDTO debug(ApiDefinitionRunRequest request) {
|
||||||
ApiResourceRunRequest runRequest = apiExecuteService.getApiResourceRunRequest(request);
|
ApiResourceRunRequest runRequest = apiExecuteService.getApiResourceRunRequest(request);
|
||||||
EnvironmentInfoDTO environmentInfoDTO = environmentService.get(request.getEnvironmentId());
|
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());
|
TaskRequestDTO taskRequest = apiExecuteService.getTaskRequest(request.getReportId(), request.getId(), request.getProjectId());
|
||||||
taskRequest.setSaveResult(false);
|
TaskInfo taskInfo = taskRequest.getTaskInfo();
|
||||||
taskRequest.setRealTime(true);
|
taskInfo.setSaveResult(false);
|
||||||
taskRequest.setResourceType(ApiResourceType.API.name());
|
taskInfo.setRealTime(true);
|
||||||
taskRequest.setRunMode(apiExecuteService.getDebugRunModule(request.getFrontendDebug()));
|
taskInfo.setResourceType(ApiResourceType.API.name());
|
||||||
|
taskInfo.setRunMode(apiExecuteService.getDebugRunModule(request.getFrontendDebug()));
|
||||||
|
|
||||||
AbstractMsTestElement msTestElement = runRequest.getTestElement();
|
AbstractMsTestElement msTestElement = runRequest.getTestElement();
|
||||||
|
|
||||||
|
|
|
@ -1,23 +1,14 @@
|
||||||
package io.metersphere.api.service.definition;
|
package io.metersphere.api.service.definition;
|
||||||
|
|
||||||
import io.metersphere.api.domain.*;
|
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.dto.definition.ApiTestCaseBatchRunRequest;
|
||||||
import io.metersphere.api.mapper.*;
|
import io.metersphere.api.mapper.*;
|
||||||
import io.metersphere.api.service.ApiBatchRunBaseService;
|
import io.metersphere.api.service.ApiBatchRunBaseService;
|
||||||
import io.metersphere.api.service.ApiCommonService;
|
|
||||||
import io.metersphere.api.service.ApiExecuteService;
|
import io.metersphere.api.service.ApiExecuteService;
|
||||||
import io.metersphere.api.service.queue.ApiExecutionQueueService;
|
import io.metersphere.api.service.queue.ApiExecutionQueueService;
|
||||||
import io.metersphere.api.service.queue.ApiExecutionSetService;
|
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.constants.*;
|
||||||
import io.metersphere.sdk.dto.api.task.ApiRunModeConfigDTO;
|
import io.metersphere.sdk.dto.api.task.*;
|
||||||
import io.metersphere.sdk.dto.api.task.CollectionReportDTO;
|
|
||||||
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
|
|
||||||
import io.metersphere.sdk.dto.queue.ExecutionQueue;
|
import io.metersphere.sdk.dto.queue.ExecutionQueue;
|
||||||
import io.metersphere.sdk.dto.queue.ExecutionQueueDetail;
|
import io.metersphere.sdk.dto.queue.ExecutionQueueDetail;
|
||||||
import io.metersphere.sdk.util.BeanUtils;
|
import io.metersphere.sdk.util.BeanUtils;
|
||||||
|
@ -34,7 +25,6 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
@ -47,14 +37,10 @@ public class ApiTestCaseBatchRunService {
|
||||||
@Resource
|
@Resource
|
||||||
private ExtApiTestCaseMapper extApiTestCaseMapper;
|
private ExtApiTestCaseMapper extApiTestCaseMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private ApiTestCaseBlobMapper apiTestCaseBlobMapper;
|
|
||||||
@Resource
|
|
||||||
private ApiTestCaseService apiTestCaseService;
|
private ApiTestCaseService apiTestCaseService;
|
||||||
@Resource
|
@Resource
|
||||||
private ApiExecuteService apiExecuteService;
|
private ApiExecuteService apiExecuteService;
|
||||||
@Resource
|
@Resource
|
||||||
private EnvironmentService environmentService;
|
|
||||||
@Resource
|
|
||||||
private ApiExecutionQueueService apiExecutionQueueService;
|
private ApiExecutionQueueService apiExecutionQueueService;
|
||||||
@Resource
|
@Resource
|
||||||
private ApiExecutionSetService apiExecutionSetService;
|
private ApiExecutionSetService apiExecutionSetService;
|
||||||
|
@ -63,10 +49,6 @@ public class ApiTestCaseBatchRunService {
|
||||||
@Resource
|
@Resource
|
||||||
private ApiBatchRunBaseService apiBatchRunBaseService;
|
private ApiBatchRunBaseService apiBatchRunBaseService;
|
||||||
@Resource
|
@Resource
|
||||||
private ApiCommonService apiCommonService;
|
|
||||||
@Resource
|
|
||||||
private ApiDefinitionMapper apiDefinitionMapper;
|
|
||||||
@Resource
|
|
||||||
private ApiReportMapper apiReportMapper;
|
private ApiReportMapper apiReportMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private ApiReportDetailMapper apiReportDetailMapper;
|
private ApiReportDetailMapper apiReportDetailMapper;
|
||||||
|
@ -168,49 +150,32 @@ public class ApiTestCaseBatchRunService {
|
||||||
|
|
||||||
// 集成报告,执行前先设置成 RUNNING
|
// 集成报告,执行前先设置成 RUNNING
|
||||||
setRunningIntegrateReport(runModeConfig);
|
setRunningIntegrateReport(runModeConfig);
|
||||||
|
List<TaskItem> taskItems = new ArrayList<>(ids.size());
|
||||||
|
|
||||||
// 分批查询
|
// 这里ID顺序和队列的ID顺序保持一致
|
||||||
SubListUtils.dealForSubList(ids, 100, subIds -> {
|
for (String id : ids) {
|
||||||
|
ApiTestCase apiTestCase = apiCaseMap.get(id);
|
||||||
|
|
||||||
AtomicInteger errorCount = new AtomicInteger();
|
if (apiTestCase == null) {
|
||||||
Map<String, ApiTestCaseBlob> apiTestCaseBlobMap = apiTestCaseService.getBlobByIds(subIds).stream()
|
if (runModeConfig.isIntegratedReport()) {
|
||||||
.collect(Collectors.toMap(ApiTestCaseBlob::getId, Function.identity()));
|
// 用例不存在,则在执行集合中删除
|
||||||
|
apiExecutionSetService.removeItem(runModeConfig.getCollectionReport().getReportId(), id);
|
||||||
// 获取用例和定义信息的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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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();
|
String resourceId = queueDetail.getResourceId();
|
||||||
|
|
||||||
ApiTestCase apiTestCase = apiTestCaseMapper.selectByPrimaryKey(resourceId);
|
ApiTestCase apiTestCase = apiTestCaseMapper.selectByPrimaryKey(resourceId);
|
||||||
ApiTestCaseBlob apiTestCaseBlob = apiTestCaseBlobMapper.selectByPrimaryKey(resourceId);
|
|
||||||
|
|
||||||
String reportId;
|
String reportId;
|
||||||
if (runModeConfig.isIntegratedReport()) {
|
if (runModeConfig.isIntegratedReport()) {
|
||||||
|
@ -323,41 +287,39 @@ public class ApiTestCaseBatchRunService {
|
||||||
LogUtils.info("当前执行任务的用例已删除 {}", resourceId);
|
LogUtils.info("当前执行任务的用例已删除 {}", resourceId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey(apiTestCase.getApiDefinitionId());
|
|
||||||
|
|
||||||
TaskRequestDTO taskRequest = getTaskRequestDTO(reportId, apiTestCase, runModeConfig);
|
TaskRequestDTO taskRequest = getTaskRequestDTO(reportId, apiTestCase, runModeConfig);
|
||||||
taskRequest.setQueueId(queue.getQueueId());
|
taskRequest.getTaskInfo().setQueueId(queue.getQueueId());
|
||||||
taskRequest.setRequestCount(1L);
|
taskRequest.getTaskItem().setRequestCount(1L);
|
||||||
execute(taskRequest, apiTestCase, apiTestCaseBlob, BeanUtils.copyBean(new ApiDefinitionExecuteInfo(), apiDefinition));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
apiExecuteService.execute(taskRequest);
|
||||||
* 执行批量的单个任务
|
|
||||||
*
|
|
||||||
* @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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private TaskRequestDTO getTaskRequestDTO(String reportId, ApiTestCase apiTestCase, ApiRunModeConfigDTO runModeConfig) {
|
private TaskRequestDTO getTaskRequestDTO(String reportId, ApiTestCase apiTestCase, ApiRunModeConfigDTO runModeConfig) {
|
||||||
TaskRequestDTO taskRequest = apiTestCaseService.getTaskRequest(reportId, apiTestCase.getId(), apiTestCase.getProjectId(), ApiExecuteRunMode.RUN.name());
|
TaskRequestDTO taskRequest = new TaskRequestDTO();
|
||||||
taskRequest.setSaveResult(true);
|
TaskItem taskItem = apiExecuteService.getTaskItem(reportId, apiTestCase.getId());
|
||||||
taskRequest.setRealTime(false);
|
TaskInfo taskInfo = getTaskInfo(apiTestCase.getProjectId(), runModeConfig);
|
||||||
taskRequest.setRunModeConfig(runModeConfig);
|
taskRequest.setTaskInfo(taskInfo);
|
||||||
|
taskRequest.setTaskItem(taskItem);
|
||||||
return taskRequest;
|
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) {
|
private ApiReport getApiReport(ApiRunModeConfigDTO runModeConfig, ApiTestCase apiTestCase, String userId) {
|
||||||
ApiReport apiReport = getApiReport(runModeConfig, 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.setName(apiTestCase.getName() + "_" + DateUtils.getTimeString(System.currentTimeMillis()));
|
||||||
apiReport.setProjectId(apiTestCase.getProjectId());
|
apiReport.setProjectId(apiTestCase.getProjectId());
|
||||||
apiReport.setTriggerMode(TaskTriggerMode.BATCH.name());
|
apiReport.setTriggerMode(TaskTriggerMode.BATCH.name());
|
||||||
|
@ -403,18 +365,6 @@ public class ApiTestCaseBatchRunService {
|
||||||
return apiReport;
|
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) {
|
public void updateStopOnFailureApiReport(ExecutionQueue queue) {
|
||||||
ApiRunModeConfigDTO runModeConfig = queue.getRunModeConfig();
|
ApiRunModeConfigDTO runModeConfig = queue.getRunModeConfig();
|
||||||
|
|
|
@ -25,7 +25,7 @@ import io.metersphere.project.service.MoveNodeService;
|
||||||
import io.metersphere.sdk.constants.*;
|
import io.metersphere.sdk.constants.*;
|
||||||
import io.metersphere.sdk.domain.Environment;
|
import io.metersphere.sdk.domain.Environment;
|
||||||
import io.metersphere.sdk.domain.EnvironmentExample;
|
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.exception.MSException;
|
||||||
import io.metersphere.sdk.mapper.EnvironmentMapper;
|
import io.metersphere.sdk.mapper.EnvironmentMapper;
|
||||||
import io.metersphere.sdk.util.*;
|
import io.metersphere.sdk.util.*;
|
||||||
|
@ -693,16 +693,18 @@ public class ApiTestCaseService extends MoveNodeService {
|
||||||
String poolId = apiExecuteService.getProjectApiResourcePoolId(apiTestCase.getProjectId());
|
String poolId = apiExecuteService.getProjectApiResourcePoolId(apiTestCase.getProjectId());
|
||||||
|
|
||||||
TaskRequestDTO taskRequest = getTaskRequest(reportId, apiTestCase.getId(), apiTestCase.getProjectId(), ApiExecuteRunMode.RUN.name());
|
TaskRequestDTO taskRequest = getTaskRequest(reportId, apiTestCase.getId(), apiTestCase.getProjectId(), ApiExecuteRunMode.RUN.name());
|
||||||
taskRequest.getRunModeConfig().setPoolId(poolId);
|
TaskItem taskItem = taskRequest.getTaskItem();
|
||||||
taskRequest.setSaveResult(true);
|
TaskInfo taskInfo = taskRequest.getTaskInfo();
|
||||||
|
taskInfo.getRunModeConfig().setPoolId(poolId);
|
||||||
|
taskInfo.setSaveResult(true);
|
||||||
|
|
||||||
if (StringUtils.isEmpty(taskRequest.getReportId())) {
|
if (StringUtils.isEmpty(taskItem.getReportId())) {
|
||||||
taskRequest.setRealTime(false);
|
taskInfo.setRealTime(false);
|
||||||
reportId = IDGenerator.nextStr();
|
reportId = IDGenerator.nextStr();
|
||||||
taskRequest.setReportId(reportId);
|
taskItem.setReportId(reportId);
|
||||||
} else {
|
} else {
|
||||||
// 如果传了报告ID,则实时获取结果
|
// 如果传了报告ID,则实时获取结果
|
||||||
taskRequest.setRealTime(true);
|
taskInfo.setRealTime(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化报告
|
// 初始化报告
|
||||||
|
@ -721,8 +723,8 @@ public class ApiTestCaseService extends MoveNodeService {
|
||||||
public TaskRequestDTO debug(ApiCaseRunRequest request) {
|
public TaskRequestDTO debug(ApiCaseRunRequest request) {
|
||||||
TaskRequestDTO taskRequest = getTaskRequest(request.getReportId(), request.getId(),
|
TaskRequestDTO taskRequest = getTaskRequest(request.getReportId(), request.getId(),
|
||||||
request.getProjectId(), apiExecuteService.getDebugRunModule(request.getFrontendDebug()));
|
request.getProjectId(), apiExecuteService.getDebugRunModule(request.getFrontendDebug()));
|
||||||
taskRequest.setSaveResult(false);
|
taskRequest.getTaskInfo().setSaveResult(false);
|
||||||
taskRequest.setRealTime(true);
|
taskRequest.getTaskInfo().setRealTime(true);
|
||||||
|
|
||||||
ApiResourceRunRequest runRequest = apiExecuteService.getApiResourceRunRequest(request);
|
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) {
|
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);
|
ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey(apiDefinitionId);
|
||||||
|
|
||||||
|
@ -743,6 +745,49 @@ public class ApiTestCaseService extends MoveNodeService {
|
||||||
return apiExecuteService.apiExecute(runRequest, taskRequest, apiParamConfig);
|
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) {
|
public TaskRequestDTO getTaskRequest(String reportId, String resourceId, String projectId, String runModule) {
|
||||||
TaskRequestDTO taskRequest = apiExecuteService.getTaskRequest(reportId, resourceId, projectId);
|
TaskRequestDTO taskRequest = new TaskRequestDTO();
|
||||||
taskRequest.setResourceType(ApiResourceType.API_CASE.name());
|
TaskItem taskItem = apiExecuteService.getTaskItem(reportId, resourceId);
|
||||||
taskRequest.setRunMode(runModule);
|
TaskInfo taskInfo = getTaskInfo(projectId, runModule);
|
||||||
|
taskRequest.setTaskInfo(taskInfo);
|
||||||
|
taskRequest.setTaskItem(taskItem);
|
||||||
return taskRequest;
|
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
|
@Override
|
||||||
public void updatePos(String id, long pos) {
|
public void updatePos(String id, long pos) {
|
||||||
extApiTestCaseMapper.updatePos(id, pos);
|
extApiTestCaseMapper.updatePos(id, pos);
|
||||||
|
|
|
@ -23,12 +23,16 @@ public class ApiExecutionSetService {
|
||||||
*/
|
*/
|
||||||
public void initSet(String setId, List<String> resourceIds) {
|
public void initSet(String setId, List<String> resourceIds) {
|
||||||
resourceIds.forEach(resourceId -> {
|
resourceIds.forEach(resourceId -> {
|
||||||
String key = SET_PREFIX + setId;
|
String key = getKey(setId);
|
||||||
redisTemplate.opsForSet().add(key, resourceId);
|
redisTemplate.opsForSet().add(key, resourceId);
|
||||||
redisTemplate.expire(key, 1, TimeUnit.DAYS);
|
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.ApiScenarioRecord;
|
||||||
import io.metersphere.api.domain.ApiScenarioReport;
|
import io.metersphere.api.domain.ApiScenarioReport;
|
||||||
import io.metersphere.api.domain.ApiScenarioReportStep;
|
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.ApiScenarioBatchRunRequest;
|
||||||
import io.metersphere.api.dto.scenario.ApiScenarioDetail;
|
import io.metersphere.api.dto.scenario.ApiScenarioDetail;
|
||||||
import io.metersphere.api.dto.scenario.ApiScenarioParseParam;
|
import io.metersphere.api.mapper.ApiScenarioMapper;
|
||||||
import io.metersphere.api.dto.scenario.ApiScenarioStepDTO;
|
|
||||||
import io.metersphere.api.mapper.ApiScenarioReportMapper;
|
import io.metersphere.api.mapper.ApiScenarioReportMapper;
|
||||||
import io.metersphere.api.mapper.ExtApiScenarioMapper;
|
import io.metersphere.api.mapper.ExtApiScenarioMapper;
|
||||||
import io.metersphere.api.service.ApiBatchRunBaseService;
|
import io.metersphere.api.service.ApiBatchRunBaseService;
|
||||||
import io.metersphere.api.service.ApiExecuteService;
|
import io.metersphere.api.service.ApiExecuteService;
|
||||||
import io.metersphere.api.service.queue.ApiExecutionQueueService;
|
import io.metersphere.api.service.queue.ApiExecutionQueueService;
|
||||||
import io.metersphere.api.service.queue.ApiExecutionSetService;
|
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.constants.*;
|
||||||
import io.metersphere.sdk.dto.api.task.ApiRunModeConfigDTO;
|
import io.metersphere.sdk.dto.api.task.*;
|
||||||
import io.metersphere.sdk.dto.api.task.CollectionReportDTO;
|
|
||||||
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
|
|
||||||
import io.metersphere.sdk.dto.queue.ExecutionQueue;
|
import io.metersphere.sdk.dto.queue.ExecutionQueue;
|
||||||
import io.metersphere.sdk.dto.queue.ExecutionQueueDetail;
|
import io.metersphere.sdk.dto.queue.ExecutionQueueDetail;
|
||||||
import io.metersphere.sdk.util.BeanUtils;
|
import io.metersphere.sdk.util.BeanUtils;
|
||||||
import io.metersphere.sdk.util.DateUtils;
|
import io.metersphere.sdk.util.DateUtils;
|
||||||
import io.metersphere.sdk.util.LogUtils;
|
import io.metersphere.sdk.util.LogUtils;
|
||||||
import io.metersphere.sdk.util.SubListUtils;
|
import io.metersphere.sdk.util.SubListUtils;
|
||||||
import io.metersphere.system.dto.pool.TestResourcePoolReturnDTO;
|
|
||||||
import io.metersphere.system.uid.IDGenerator;
|
import io.metersphere.system.uid.IDGenerator;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
import org.apache.commons.lang3.BooleanUtils;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@ -45,7 +33,6 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@ -68,9 +55,10 @@ public class ApiScenarioBatchRunService {
|
||||||
private ApiBatchRunBaseService apiBatchRunBaseService;
|
private ApiBatchRunBaseService apiBatchRunBaseService;
|
||||||
@Resource
|
@Resource
|
||||||
private ExtApiScenarioMapper extApiScenarioMapper;
|
private ExtApiScenarioMapper extApiScenarioMapper;
|
||||||
|
@Resource
|
||||||
@Value("${spring.datasource.hikari.maximum-pool-size}")
|
private ApiScenarioMapper apiScenarioMapper;
|
||||||
private int maximumPoolSize;
|
@Resource
|
||||||
|
private ApiScenarioRunService apiScenarioRunService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 异步批量执行
|
* 异步批量执行
|
||||||
|
@ -148,31 +136,17 @@ public class ApiScenarioBatchRunService {
|
||||||
// 集成报告,执行前先设置成 RUNNING
|
// 集成报告,执行前先设置成 RUNNING
|
||||||
setRunningIntegrateReport(runModeConfig);
|
setRunningIntegrateReport(runModeConfig);
|
||||||
|
|
||||||
TestResourcePoolReturnDTO testResourcePoolDTO = apiExecuteService.getGetResourcePoolNodeDTO(runModeConfig, request.getProjectId());
|
List<TaskItem> taskItems = ids.stream()
|
||||||
List<ApiScenarioDetail> apiScenarioDetails = apiScenarioService.getForRuns(ids);
|
.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())) {
|
apiExecuteService.batchExecute(taskRequest);
|
||||||
// 独立部署执行专属服务,线程池执行
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
private Map<String, String> initReport(List<String> ids, ApiRunModeConfigDTO runModeConfig, String userId) {
|
||||||
Map<String, String> scenarioReportMap = new HashMap<>();
|
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
|
* 集成报告,执行前先设置成 RUNNING
|
||||||
*
|
*
|
||||||
|
@ -288,81 +251,53 @@ public class ApiScenarioBatchRunService {
|
||||||
*/
|
*/
|
||||||
public void executeNextTask(ExecutionQueue queue, ExecutionQueueDetail queueDetail) {
|
public void executeNextTask(ExecutionQueue queue, ExecutionQueueDetail queueDetail) {
|
||||||
ApiRunModeConfigDTO runModeConfig = queue.getRunModeConfig();
|
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) {
|
if (apiScenarioDetail == null) {
|
||||||
LogUtils.info("当前执行任务的用例已删除 {}", queueDetail.getResourceId());
|
LogUtils.info("当前执行任务的用例已删除 {}", queueDetail.getResourceId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String reportId;
|
String reportId;
|
||||||
if (runModeConfig.isIntegratedReport()) {
|
if (runModeConfig.isIntegratedReport()) {
|
||||||
reportId = IDGenerator.nextStr();
|
reportId = IDGenerator.nextStr();
|
||||||
} else {
|
} else {
|
||||||
// 独立报告,执行到当前任务时初始化报告
|
// 独立报告,执行到当前任务时初始化报告
|
||||||
reportId = initScenarioReport(runModeConfig, apiScenarioDetail, queue.getUserId()).getApiScenarioReportId();
|
reportId = initScenarioReport(runModeConfig, apiScenario, queue.getUserId()).getApiScenarioReportId();
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskRequestDTO taskRequest = getTaskRequestDTO(reportId, apiScenarioDetail, queue.getRunModeConfig());
|
TaskRequestDTO taskRequest = getTaskRequestDTO(apiScenario.getProjectId(), queue.getRunModeConfig());
|
||||||
taskRequest.setQueueId(queue.getQueueId());
|
TaskItem taskItem = apiExecuteService.getTaskItem(reportId, queueDetail.getResourceId());
|
||||||
execute(taskRequest, apiScenarioDetail);
|
taskRequest.setTaskItem(taskItem);
|
||||||
|
taskRequest.getTaskInfo().setQueueId(queue.getQueueId());
|
||||||
|
|
||||||
|
apiExecuteService.execute(taskRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private TaskRequestDTO getTaskRequestDTO(String projectId, ApiRunModeConfigDTO runModeConfig) {
|
||||||
* 执行批量的单个任务
|
TaskRequestDTO taskRequest = new TaskRequestDTO();
|
||||||
*/
|
TaskInfo taskInfo = getTaskInfo(projectId, runModeConfig);
|
||||||
public void execute(TaskRequestDTO taskRequest, ApiScenarioDetail apiScenarioDetail) {
|
taskRequest.setTaskInfo(taskInfo);
|
||||||
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);
|
|
||||||
return taskRequest;
|
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 apiScenarioReport = getScenarioReport(runModeConfig, apiScenario, userId);
|
||||||
apiScenarioReport.setId(IDGenerator.nextStr());
|
apiScenarioReport.setId(IDGenerator.nextStr());
|
||||||
// 创建报告和用例的关联关系
|
// 创建报告和用例的关联关系
|
||||||
ApiScenarioRecord apiScenarioRecord = apiScenarioService.getApiScenarioRecord(apiScenario, apiScenarioReport);
|
ApiScenarioRecord apiScenarioRecord = apiScenarioRunService.getApiScenarioRecord(apiScenario, apiScenarioReport);
|
||||||
apiScenarioReportService.insertApiScenarioReport(List.of(apiScenarioReport), List.of(apiScenarioRecord));
|
apiScenarioReportService.insertApiScenarioReport(List.of(apiScenarioReport), List.of(apiScenarioRecord));
|
||||||
return apiScenarioRecord;
|
return apiScenarioRecord;
|
||||||
}
|
}
|
||||||
|
@ -383,7 +318,7 @@ public class ApiScenarioBatchRunService {
|
||||||
|
|
||||||
private ApiScenarioReport getScenarioReport(ApiRunModeConfigDTO runModeConfig, ApiScenario apiScenario, String userId) {
|
private ApiScenarioReport getScenarioReport(ApiRunModeConfigDTO runModeConfig, ApiScenario apiScenario, String userId) {
|
||||||
ApiScenarioReport apiScenarioReport = getScenarioReport(runModeConfig, 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.setName(apiScenario.getName() + "_" + DateUtils.getTimeString(System.currentTimeMillis()));
|
||||||
apiScenarioReport.setProjectId(apiScenario.getProjectId());
|
apiScenarioReport.setProjectId(apiScenario.getProjectId());
|
||||||
apiScenarioReport.setTriggerMode(TaskTriggerMode.BATCH.name());
|
apiScenarioReport.setTriggerMode(TaskTriggerMode.BATCH.name());
|
||||||
|
@ -391,7 +326,7 @@ public class ApiScenarioBatchRunService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ApiScenarioReport getScenarioReport(ApiRunModeConfigDTO runModeConfig, String userId) {
|
public ApiScenarioReport getScenarioReport(ApiRunModeConfigDTO runModeConfig, String userId) {
|
||||||
ApiScenarioReport apiScenarioReport = apiScenarioService.getScenarioReport(userId);
|
ApiScenarioReport apiScenarioReport = apiScenarioRunService.getScenarioReport(userId);
|
||||||
apiScenarioReport.setEnvironmentId(runModeConfig.getEnvironmentId());
|
apiScenarioReport.setEnvironmentId(runModeConfig.getEnvironmentId());
|
||||||
apiScenarioReport.setRunMode(runModeConfig.getRunMode());
|
apiScenarioReport.setRunMode(runModeConfig.getRunMode());
|
||||||
apiScenarioReport.setPoolId(runModeConfig.getPoolId());
|
apiScenarioReport.setPoolId(runModeConfig.getPoolId());
|
||||||
|
@ -399,22 +334,7 @@ public class ApiScenarioBatchRunService {
|
||||||
return apiScenarioReport;
|
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) {
|
public void updateStopOnFailureReport(ExecutionQueue queue) {
|
||||||
ApiRunModeConfigDTO runModeConfig = queue.getRunModeConfig();
|
ApiRunModeConfigDTO runModeConfig = queue.getRunModeConfig();
|
||||||
|
@ -425,18 +345,18 @@ public class ApiScenarioBatchRunService {
|
||||||
}
|
}
|
||||||
long requestCount = 0L;
|
long requestCount = 0L;
|
||||||
while (queueDetail != null) {
|
while (queueDetail != null) {
|
||||||
ApiScenarioDetail apiScenarioDetail = apiScenarioService.getForRun(queueDetail.getResourceId());
|
ApiScenarioDetail apiScenarioDetail = apiScenarioRunService.getForRun(queueDetail.getResourceId());
|
||||||
if (apiScenarioDetail == null) {
|
if (apiScenarioDetail == null) {
|
||||||
LogUtils.info("当前场景已删除 {}", queueDetail.getResourceId());
|
LogUtils.info("当前场景已删除 {}", queueDetail.getResourceId());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Long requestCountItem = getRequestCount(apiScenarioDetail.getSteps());
|
Long requestCountItem = apiScenarioRunService.getRequestCount(apiScenarioDetail.getSteps());
|
||||||
requestCount += requestCountItem;
|
requestCount += requestCountItem;
|
||||||
|
|
||||||
// 初始化报告步骤
|
// 初始化报告步骤
|
||||||
if (runModeConfig.isIntegratedReport()) {
|
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());
|
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.domain.*;
|
||||||
import io.metersphere.api.dto.*;
|
import io.metersphere.api.dto.*;
|
||||||
import io.metersphere.api.dto.debug.ApiFileResourceUpdateRequest;
|
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.ExecutePageRequest;
|
||||||
import io.metersphere.api.dto.definition.ExecuteReportDTO;
|
import io.metersphere.api.dto.definition.ExecuteReportDTO;
|
||||||
import io.metersphere.api.dto.request.ApiTransferRequest;
|
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.controller.MsScriptElement;
|
||||||
import io.metersphere.api.dto.request.http.MsHTTPElement;
|
import io.metersphere.api.dto.request.http.MsHTTPElement;
|
||||||
import io.metersphere.api.dto.response.ApiScenarioBatchOperationResponse;
|
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.StepParser;
|
||||||
import io.metersphere.api.parser.step.StepParserFactory;
|
import io.metersphere.api.parser.step.StepParserFactory;
|
||||||
import io.metersphere.api.service.ApiCommonService;
|
import io.metersphere.api.service.ApiCommonService;
|
||||||
import io.metersphere.api.service.ApiExecuteService;
|
|
||||||
import io.metersphere.api.service.ApiFileResourceService;
|
import io.metersphere.api.service.ApiFileResourceService;
|
||||||
import io.metersphere.api.service.definition.ApiDefinitionModuleService;
|
import io.metersphere.api.service.definition.ApiDefinitionModuleService;
|
||||||
import io.metersphere.api.service.definition.ApiDefinitionService;
|
import io.metersphere.api.service.definition.ApiDefinitionService;
|
||||||
import io.metersphere.api.service.definition.ApiTestCaseService;
|
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.ApiDataUtils;
|
||||||
import io.metersphere.api.utils.ApiScenarioBatchOperationUtils;
|
import io.metersphere.api.utils.ApiScenarioBatchOperationUtils;
|
||||||
import io.metersphere.functional.domain.FunctionalCaseTestExample;
|
import io.metersphere.functional.domain.FunctionalCaseTestExample;
|
||||||
import io.metersphere.functional.mapper.FunctionalCaseTestMapper;
|
import io.metersphere.functional.mapper.FunctionalCaseTestMapper;
|
||||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
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.FileAssociation;
|
||||||
import io.metersphere.project.domain.FileMetadata;
|
import io.metersphere.project.domain.FileMetadata;
|
||||||
import io.metersphere.project.domain.Project;
|
import io.metersphere.project.domain.Project;
|
||||||
import io.metersphere.project.domain.ProjectExample;
|
import io.metersphere.project.domain.ProjectExample;
|
||||||
import io.metersphere.project.dto.MoveNodeSortDTO;
|
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.ExtBaseProjectVersionMapper;
|
||||||
import io.metersphere.project.mapper.ProjectMapper;
|
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.project.service.MoveNodeService;
|
||||||
import io.metersphere.sdk.constants.*;
|
import io.metersphere.sdk.constants.*;
|
||||||
import io.metersphere.sdk.domain.Environment;
|
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.EnvironmentGroup;
|
||||||
import io.metersphere.sdk.domain.EnvironmentGroupExample;
|
import io.metersphere.sdk.domain.EnvironmentGroupExample;
|
||||||
import io.metersphere.sdk.dto.api.task.ApiRunModeConfigDTO;
|
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.exception.MSException;
|
||||||
import io.metersphere.sdk.file.FileCopyRequest;
|
import io.metersphere.sdk.file.FileCopyRequest;
|
||||||
import io.metersphere.sdk.file.MinioRepository;
|
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.mapper.ScheduleMapper;
|
||||||
import io.metersphere.system.notice.constants.NoticeConstants;
|
import io.metersphere.system.notice.constants.NoticeConstants;
|
||||||
import io.metersphere.system.schedule.ScheduleService;
|
import io.metersphere.system.schedule.ScheduleService;
|
||||||
import io.metersphere.system.service.ApiPluginService;
|
|
||||||
import io.metersphere.system.service.OperationHistoryService;
|
import io.metersphere.system.service.OperationHistoryService;
|
||||||
import io.metersphere.system.service.UserLoginService;
|
import io.metersphere.system.service.UserLoginService;
|
||||||
import io.metersphere.system.uid.IDGenerator;
|
import io.metersphere.system.uid.IDGenerator;
|
||||||
|
@ -149,8 +137,6 @@ public class ApiScenarioService extends MoveNodeService {
|
||||||
@Resource
|
@Resource
|
||||||
private ApiScenarioBlobMapper apiScenarioBlobMapper;
|
private ApiScenarioBlobMapper apiScenarioBlobMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private ApiExecuteService apiExecuteService;
|
|
||||||
@Resource
|
|
||||||
private ApiDefinitionService apiDefinitionService;
|
private ApiDefinitionService apiDefinitionService;
|
||||||
@Resource
|
@Resource
|
||||||
private ApiTestCaseService apiTestCaseService;
|
private ApiTestCaseService apiTestCaseService;
|
||||||
|
@ -163,12 +149,6 @@ public class ApiScenarioService extends MoveNodeService {
|
||||||
@Resource
|
@Resource
|
||||||
private ScheduleMapper scheduleMapper;
|
private ScheduleMapper scheduleMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private EnvironmentService environmentService;
|
|
||||||
@Resource
|
|
||||||
private EnvironmentGroupService environmentGroupService;
|
|
||||||
@Resource
|
|
||||||
private ApiPluginService apiPluginService;
|
|
||||||
@Resource
|
|
||||||
private ProjectMapper projectMapper;
|
private ProjectMapper projectMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private ExtApiDefinitionMapper extApiDefinitionMapper;
|
private ExtApiDefinitionMapper extApiDefinitionMapper;
|
||||||
|
@ -179,14 +159,10 @@ public class ApiScenarioService extends MoveNodeService {
|
||||||
@Resource
|
@Resource
|
||||||
private ExtApiTestCaseMapper extApiTestCaseMapper;
|
private ExtApiTestCaseMapper extApiTestCaseMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private ApiDefinitionModuleService apiDefinitionModuleService;
|
|
||||||
@Resource
|
|
||||||
private OperationHistoryService operationHistoryService;
|
private OperationHistoryService operationHistoryService;
|
||||||
@Resource
|
@Resource
|
||||||
private ApiCommonService apiCommonService;
|
private ApiCommonService apiCommonService;
|
||||||
@Resource
|
@Resource
|
||||||
private ApiScenarioReportService apiScenarioReportService;
|
|
||||||
@Resource
|
|
||||||
private ApiScenarioReportMapper apiScenarioReportMapper;
|
private ApiScenarioReportMapper apiScenarioReportMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private ApiScenarioNoticeService apiScenarioNoticeService;
|
private ApiScenarioNoticeService apiScenarioNoticeService;
|
||||||
|
@ -930,7 +906,7 @@ public class ApiScenarioService extends MoveNodeService {
|
||||||
return StringUtils.equals(refType, ApiScenarioStepRefType.PARTIAL_REF.name());
|
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());
|
return StringUtils.equalsAny(refType, ApiScenarioStepRefType.REF.name(), ApiScenarioStepRefType.PARTIAL_REF.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1005,7 +981,7 @@ public class ApiScenarioService extends MoveNodeService {
|
||||||
* copyFromStepId 的 detail
|
* copyFromStepId 的 detail
|
||||||
* isNew 的资源的 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)) {
|
if (CollectionUtils.isEmpty(steps)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1338,625 +1314,19 @@ public class ApiScenarioService extends MoveNodeService {
|
||||||
return ServiceUtils.checkResourceExist(apiScenarioMapper.selectByPrimaryKey(id), "permission.system_api_scenario.name");
|
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) {
|
public boolean isRequestStep(ApiScenarioStepCommonDTO step) {
|
||||||
ApiScenarioStepType scenarioStepType = EnumValidator.validateEnum(ApiScenarioStepType.class, step.getStepType());
|
ApiScenarioStepType scenarioStepType = EnumValidator.validateEnum(ApiScenarioStepType.class, step.getStepType());
|
||||||
return scenarioStepType == null ? false : scenarioStepType.isRequest();
|
return scenarioStepType == null ? false : scenarioStepType.isRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public static boolean isScenarioStep(String stepType) {
|
||||||
* 预生成用例的执行报告
|
|
||||||
*
|
|
||||||
* @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) {
|
|
||||||
return StringUtils.equals(stepType, ApiScenarioStepType.API_SCENARIO.name());
|
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());
|
String stepDetail = stepDetailMap.get(step.getId());
|
||||||
if (!isPartialRef(step) || StringUtils.isBlank(stepDetail)) {
|
if (!isPartialRef(step) || StringUtils.isBlank(stepDetail)) {
|
||||||
return;
|
return;
|
||||||
|
@ -1998,17 +1368,6 @@ public class ApiScenarioService extends MoveNodeService {
|
||||||
StringUtils.equals(step.getRefType(), ApiScenarioStepRefType.PARTIAL_REF.name());
|
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())));
|
.collect(Collectors.toMap(ApiScenarioStepBlob::getId, blob -> new String(blob.getContent())));
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> getHasDetailStepIds(List<? extends ApiScenarioStepCommonDTO> steps, Map<String, Object> stepDetailsParam) {
|
public List<ApiScenarioStepBlob> getStepBlobByIds(List<String> stepIds) {
|
||||||
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) {
|
|
||||||
if (CollectionUtils.isEmpty(stepIds)) {
|
if (CollectionUtils.isEmpty(stepIds)) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
@ -2089,43 +1399,6 @@ public class ApiScenarioService extends MoveNodeService {
|
||||||
return apiScenarioStepBlobMapper.selectByExampleWithBLOBs(example);
|
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) {
|
public void updateStatus(String id, String status, String userId) {
|
||||||
checkResourceExist(id);
|
checkResourceExist(id);
|
||||||
ApiScenario update = new ApiScenario();
|
ApiScenario update = new ApiScenario();
|
||||||
|
@ -2181,36 +1454,6 @@ public class ApiScenarioService extends MoveNodeService {
|
||||||
return apiScenarios.getFirst();
|
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) {
|
public ApiScenarioDetail get(String scenarioId) {
|
||||||
ApiScenario apiScenario = checkResourceIsNoDeleted(scenarioId);
|
ApiScenario apiScenario = checkResourceIsNoDeleted(scenarioId);
|
||||||
ApiScenarioDetail apiScenarioDetail = BeanUtils.copyBean(new ApiScenarioDetail(), apiScenario);
|
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);
|
return isApi(stepType) && isCopy(refType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isApi(String stepType) {
|
public boolean isApi(String stepType) {
|
||||||
return StringUtils.equals(stepType, ApiScenarioStepType.API.name());
|
return StringUtils.equals(stepType, ApiScenarioStepType.API.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isCopy(String refType) {
|
public boolean isCopy(String refType) {
|
||||||
return StringUtils.equals(refType, ApiScenarioStepRefType.COPY.name());
|
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());
|
return StringUtils.equals(stepType, ApiScenarioStepType.API_CASE.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3110,6 +2353,7 @@ public class ApiScenarioService extends MoveNodeService {
|
||||||
resourceInfo.setDelete(apiTestCase.getDeleted());
|
resourceInfo.setDelete(apiTestCase.getDeleted());
|
||||||
resourceInfo.setProjectId(apiTestCase.getProjectId());
|
resourceInfo.setProjectId(apiTestCase.getProjectId());
|
||||||
});
|
});
|
||||||
|
default -> {}
|
||||||
}
|
}
|
||||||
Optional.ofNullable(apiStepResourceInfo).ifPresent(resourceInfo -> {
|
Optional.ofNullable(apiStepResourceInfo).ifPresent(resourceInfo -> {
|
||||||
Project project = projectMapper.selectByPrimaryKey(resourceInfo.getProjectId());
|
Project project = projectMapper.selectByPrimaryKey(resourceInfo.getProjectId());
|
||||||
|
@ -3128,30 +2372,4 @@ public class ApiScenarioService extends MoveNodeService {
|
||||||
setParamFunc.accept(apiStepResourceInfo, resource);
|
setParamFunc.accept(apiStepResourceInfo, resource);
|
||||||
return apiStepResourceInfo;
|
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);
|
request.setFrontendDebug(true);
|
||||||
MvcResult mvcResult = this.requestPostWithOkAndReturn(DEBUG, request);
|
MvcResult mvcResult = this.requestPostWithOkAndReturn(DEBUG, request);
|
||||||
TaskRequestDTO taskRequestDTO = getResultData(mvcResult, TaskRequestDTO.class);
|
TaskRequestDTO taskRequestDTO = getResultData(mvcResult, TaskRequestDTO.class);
|
||||||
Assertions.assertEquals(taskRequestDTO.getReportId(), request.getReportId());
|
Assertions.assertEquals(taskRequestDTO.getTaskItem().getReportId(), request.getReportId());
|
||||||
|
|
||||||
// 测试请求体
|
// 测试请求体
|
||||||
MockMultipartFile file = getMockMultipartFile();
|
MockMultipartFile file = getMockMultipartFile();
|
||||||
|
|
|
@ -67,7 +67,7 @@ public class ApiExecuteResourceControllerTest extends BaseTest {
|
||||||
|
|
||||||
String reportId = UUID.randomUUID().toString();
|
String reportId = UUID.randomUUID().toString();
|
||||||
String testId = 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");
|
stringRedisTemplate.opsForValue().set(scriptRedisKey, "aaa");
|
||||||
mockMvc.perform(getPostRequestBuilder(FILE, fileRequest, reportId, testId))
|
mockMvc.perform(getPostRequestBuilder(FILE, fileRequest, reportId, testId))
|
||||||
.andExpect(status().isOk());
|
.andExpect(status().isOk());
|
||||||
|
|
|
@ -166,7 +166,7 @@ public class KubernetesEngineTests extends BaseTest {
|
||||||
TaskRequestDTO request = new TaskRequestDTO();
|
TaskRequestDTO request = new TaskRequestDTO();
|
||||||
ApiRunModeConfigDTO runModeConfig = new ApiRunModeConfigDTO();
|
ApiRunModeConfigDTO runModeConfig = new ApiRunModeConfigDTO();
|
||||||
runModeConfig.setPoolId(id);
|
runModeConfig.setPoolId(id);
|
||||||
request.setRunModeConfig(runModeConfig);
|
request.getTaskInfo().setRunModeConfig(runModeConfig);
|
||||||
|
|
||||||
final ApiEngine engine = EngineFactory.createApiEngine(request);
|
final ApiEngine engine = EngineFactory.createApiEngine(request);
|
||||||
engine.start();
|
engine.start();
|
||||||
|
|
|
@ -2,6 +2,7 @@ package io.metersphere.system.utils;
|
||||||
|
|
||||||
import com.bastiaanjansen.otp.TOTPGenerator;
|
import com.bastiaanjansen.otp.TOTPGenerator;
|
||||||
import io.metersphere.sdk.constants.MsHttpHeaders;
|
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.dto.api.task.TaskRequestDTO;
|
||||||
import io.metersphere.sdk.util.LogUtils;
|
import io.metersphere.sdk.util.LogUtils;
|
||||||
import io.metersphere.system.controller.handler.ResultHolder;
|
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_DEBUG = "/api/debug";
|
||||||
private static final String API_RUN = "/api/run";
|
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 HTTP_BATH = "http://%s:%s";
|
||||||
private static final String API_STOP = "/api/stop";
|
private static final String API_STOP = "/api/stop";
|
||||||
|
|
||||||
|
@ -50,6 +52,10 @@ public class TaskRunnerClient {
|
||||||
post(endpoint + API_RUN, taskRequest);
|
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 {
|
public static void stopApi(String endpoint, List<String> reportIds) throws Exception {
|
||||||
post(endpoint + API_STOP, reportIds);
|
post(endpoint + API_STOP, reportIds);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue