fix(接口测试): 执行任务开始执行时,没有设置开始时间和状态

This commit is contained in:
AgAngle 2024-10-16 14:01:35 +08:00 committed by Craftsman
parent 6536efdc96
commit 23092f013c
9 changed files with 147 additions and 22 deletions

View File

@ -6,4 +6,5 @@ package io.metersphere.sdk.constants;
*/
public class CommonConstants {
public static final String DEFAULT_NULL_VALUE = "NONE";
public static final String RUNNING_TASK_PREFIX = "RUNNING_TASK:";
}

View File

@ -48,4 +48,14 @@ public class GetRunScriptRequest implements Serializable {
* 线程ID
*/
private String threadId;
/**
* 是否是批量执行
* 包括用例的批量执行
* 测试计划的执行
*/
private Boolean batch;
/**
* 任务ID
*/
private String taskId;
}

View File

@ -102,4 +102,11 @@ public class TaskInfo implements Serializable {
* 记录执行时的环境变量
*/
private List<String> environmentVariables;
/**
* 是否是批量执行
* 包括用例的批量执行
* 测试计划的执行
*/
private Boolean batch = false;
}

View File

@ -3,17 +3,18 @@ package io.metersphere.api.service;
import io.metersphere.api.invoker.ApiExecuteCallbackServiceInvoker;
import io.metersphere.api.service.definition.ApiReportService;
import io.metersphere.api.service.scenario.ApiScenarioReportService;
import io.metersphere.sdk.constants.ApiExecuteResourceType;
import io.metersphere.sdk.constants.ApiExecuteRunMode;
import io.metersphere.sdk.constants.ExecStatus;
import io.metersphere.api.utils.TaskRunningCache;
import io.metersphere.sdk.constants.*;
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 io.metersphere.system.domain.ExecTask;
import io.metersphere.system.domain.ExecTaskItem;
import io.metersphere.system.mapper.ExecTaskItemMapper;
import io.metersphere.system.mapper.ExecTaskMapper;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
@ -27,6 +28,8 @@ import java.util.Optional;
@Transactional(rollbackFor = Exception.class)
public class ApiExecuteResourceService {
@Resource
private ExecTaskMapper execTaskMapper;
@Resource
private ExecTaskItemMapper execTaskItemMapper;
@Resource
@ -35,33 +38,17 @@ public class ApiExecuteResourceService {
private ApiScenarioReportService apiScenarioReportService;
@Resource
private StringRedisTemplate stringRedisTemplate;
@Resource
private TaskRunningCache taskRunningCache;
public GetRunScriptResult getRunScript(GetRunScriptRequest request) {
TaskItem taskItem = request.getTaskItem();
String taskItemId = taskItem.getId();
String reportId = taskItem.getReportId();
LogUtils.info("生成并获取执行脚本: {}", taskItem.getId());
ApiExecuteResourceType apiExecuteResourceType = EnumValidator.validateEnum(ApiExecuteResourceType.class, request.getResourceType());
if (!ApiExecuteRunMode.isDebug(request.getRunMode())) {
// 更新任务项状态
ExecTaskItem execTaskItem = new ExecTaskItem();
execTaskItem.setId(taskItem.getId());
execTaskItem.setStartTime(System.currentTimeMillis());
execTaskItem.setStatus(ExecStatus.RUNNING.name());
execTaskItem.setThreadId(request.getThreadId());
execTaskItemMapper.updateByPrimaryKeySelective(execTaskItem);
// 非调试执行更新报告状态
switch (apiExecuteResourceType) {
case API_SCENARIO, TEST_PLAN_API_SCENARIO, PLAN_RUN_API_SCENARIO ->
apiScenarioReportService.updateReportRunningStatus(reportId);
case API_CASE, TEST_PLAN_API_CASE, PLAN_RUN_API_CASE ->
apiReportService.updateReportRunningStatus(reportId);
default -> throw new MSException("不支持的资源类型: " + request.getResourceType());
}
updateRunningReportStatus(request);
}
if (BooleanUtils.isFalse(request.getNeedParseScript())) {
@ -75,4 +62,54 @@ public class ApiExecuteResourceService {
return ApiExecuteCallbackServiceInvoker.getRunScript(request.getResourceType(), request);
}
private void updateRunningReportStatus(GetRunScriptRequest request) {
TaskItem taskItem = request.getTaskItem();
String taskId = request.getTaskId();
String reportId = taskItem.getReportId();
ApiExecuteResourceType apiExecuteResourceType = EnumValidator.validateEnum(ApiExecuteResourceType.class, request.getResourceType());
if (request.getBatch()) {
// 设置缓存成功说明是第一个任务则设置任务的开始时间和运行状态
if (taskRunningCache.setIfAbsent(taskId)) {
// 将任务状态更新为运行中
updateTaskRunningStatus(taskId);
}
} else {
// 非批量时直接更新任务状态
updateTaskRunningStatus(taskId);
}
// 更新任务项状态
updateTaskItemRunningStatus(request);
// 非调试执行更新报告状态
switch (apiExecuteResourceType) {
case API_SCENARIO, TEST_PLAN_API_SCENARIO, PLAN_RUN_API_SCENARIO ->
apiScenarioReportService.updateReportRunningStatus(reportId);
case API_CASE, TEST_PLAN_API_CASE, PLAN_RUN_API_CASE ->
apiReportService.updateReportRunningStatus(reportId);
default -> throw new MSException("不支持的资源类型: " + request.getResourceType());
}
}
private void updateTaskRunningStatus(String taskId) {
ExecTask execTask = new ExecTask();
execTask.setId(taskId);
execTask.setStartTime(System.currentTimeMillis());
execTask.setStatus(ExecStatus.RUNNING.name());
execTaskMapper.updateByPrimaryKeySelective(execTask);
}
private void updateTaskItemRunningStatus(GetRunScriptRequest request) {
TaskItem taskItem = request.getTaskItem();
// 更新任务项状态
ExecTaskItem execTaskItem = new ExecTaskItem();
execTaskItem.setId(taskItem.getId());
execTaskItem.setStartTime(System.currentTimeMillis());
execTaskItem.setStatus(ExecStatus.RUNNING.name());
execTaskItem.setThreadId(request.getThreadId());
execTaskItemMapper.updateByPrimaryKeySelective(execTaskItem);
}
}

View File

@ -435,6 +435,7 @@ public class ApiTestCaseBatchRunService {
public TaskInfo getTaskInfo(String projectId, ApiRunModeConfigDTO runModeConfig) {
TaskInfo taskInfo = apiTestCaseService.getTaskInfo(projectId, ApiExecuteRunMode.RUN.name());
taskInfo.setBatch(true);
return apiBatchRunBaseService.setBatchRunTaskInfoParam(runModeConfig, taskInfo);
}

View File

@ -392,6 +392,7 @@ public class ApiScenarioBatchRunService {
public TaskInfo getTaskInfo(String projectId, ApiRunModeConfigDTO runModeConfig) {
TaskInfo taskInfo = apiScenarioRunService.getTaskInfo(projectId, ApiExecuteRunMode.RUN.name());
taskInfo.setBatch(true);
return apiBatchRunBaseService.setBatchRunTaskInfoParam(runModeConfig, taskInfo);
}

View File

@ -0,0 +1,66 @@
package io.metersphere.api.utils;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import io.metersphere.sdk.constants.CommonConstants;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* 记录正在运行的任务
* runningTasks 作为内存级别的一级缓存减少网络交互
* redis 作为分布式的二级缓存
* 执行结束后result-hub 清除二级缓存
*
* @Author: jianxing
* @CreateTime: 2024-10-09 10:57
*/
@Component
public class TaskRunningCache {
@Resource
private StringRedisTemplate stringRedisTemplate;
/**
* 记录正在运行的任务
*/
private final Cache<String, Boolean> runningTasks = CacheBuilder.newBuilder()
.expireAfterWrite(30, TimeUnit.SECONDS)
.build();
/**
* 如果没有缓存则设置缓存
* 设置成功则返回 true说明没有缓存
* 设置失败则返回 false说明有缓存
* @param taskId
* @return
*/
public boolean setIfAbsent(String taskId) {
Boolean hasCache = BooleanUtils.isTrue(runningTasks.getIfPresent(taskId));
if (!hasCache) {
// 原子操作没有线程安全问题
// 一级缓存没有则查询二级缓存
Boolean success = stringRedisTemplate.opsForValue()
.setIfAbsent(
getKey(taskId),
StringUtils.EMPTY,
1,
TimeUnit.DAYS
);
// 设置二级缓存
runningTasks.put(taskId, true);
return success;
}
return false;
}
private static String getKey(String taskId) {
return CommonConstants.RUNNING_TASK_PREFIX + taskId;
}
}

View File

@ -403,6 +403,7 @@ public class TestPlanApiCaseBatchRunService {
private TaskInfo getTaskInfo(String projectId, ApiRunModeConfigDTO runModeConfig) {
TaskInfo taskInfo = apiTestCaseBatchRunService.getTaskInfo(projectId, runModeConfig);
taskInfo.setBatch(true);
taskInfo.setResourceType(ApiExecuteResourceType.TEST_PLAN_API_CASE.name());
return taskInfo;
}

View File

@ -391,6 +391,7 @@ public class TestPlanApiScenarioBatchRunService {
private TaskInfo getTaskInfo(String projectId, ApiRunModeConfigDTO runModeConfig) {
TaskInfo taskInfo = apiScenarioBatchRunService.getTaskInfo(projectId, runModeConfig);
taskInfo.setBatch(true);
taskInfo.setResourceType(ApiExecuteResourceType.TEST_PLAN_API_SCENARIO.name());
return taskInfo;
}