feat(接口测试): 测试计划接口和场景批量执行

This commit is contained in:
AgAngle 2024-06-11 18:15:36 +08:00 committed by Craftsman
parent 62280513fd
commit 6b6f75ab2f
17 changed files with 795 additions and 83 deletions

View File

@ -3,7 +3,6 @@ package io.metersphere.api.dto.definition;
import io.metersphere.api.dto.ApiRunModeRequest; import io.metersphere.api.dto.ApiRunModeRequest;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import jakarta.validation.constraints.Size;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@ -15,10 +14,6 @@ public class ApiTestCaseBatchRunRequest extends ApiTestCaseBatchRequest implemen
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Schema(description = "接口pk")
@Size(max = 50, message = "{api_definition.id.length_range}")
private String apiDefinitionId;
@Valid @Valid
@Schema(description = "运行模式配置") @Schema(description = "运行模式配置")
private ApiRunModeRequest runModeConfig; private ApiRunModeRequest runModeConfig;

View File

@ -3,6 +3,7 @@ package io.metersphere.api.service;
import io.metersphere.api.domain.ApiScenarioReport; import io.metersphere.api.domain.ApiScenarioReport;
import io.metersphere.api.service.queue.ApiExecutionQueueService; import io.metersphere.api.service.queue.ApiExecutionQueueService;
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.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.LogUtils; import io.metersphere.sdk.util.LogUtils;
@ -92,4 +93,12 @@ public class ApiBatchRunBaseService {
private static String formatRate(double rate) { private static String formatRate(double rate) {
return String.format("%.2f", rate * 100); return String.format("%.2f", rate * 100);
} }
public TaskInfo setBatchRunTaskInfoParam(ApiRunModeConfigDTO runModeConfig, TaskInfo taskInfo) {
taskInfo.setSaveResult(true);
taskInfo.setRealTime(false);
taskInfo.setNeedParseScript(true);
taskInfo.setRunModeConfig(runModeConfig);
return taskInfo;
}
} }

View File

@ -311,16 +311,11 @@ public class ApiTestCaseBatchRunService {
return taskRequest; return taskRequest;
} }
private TaskInfo getTaskInfo(String projectId, ApiRunModeConfigDTO runModeConfig) { public TaskInfo getTaskInfo(String projectId, ApiRunModeConfigDTO runModeConfig) {
TaskInfo taskInfo = apiTestCaseService.getTaskInfo(projectId, ApiExecuteRunMode.RUN.name()); TaskInfo taskInfo = apiTestCaseService.getTaskInfo(projectId, ApiExecuteRunMode.RUN.name());
taskInfo.setSaveResult(true); return apiBatchRunBaseService.setBatchRunTaskInfoParam(runModeConfig, taskInfo);
taskInfo.setRealTime(false);
taskInfo.setNeedParseScript(true);
taskInfo.setRunModeConfig(runModeConfig);
return taskInfo;
} }
/** /**
* 预生成用例的执行报告 * 预生成用例的执行报告
* *
@ -346,8 +341,7 @@ public class ApiTestCaseBatchRunService {
return apiTestCaseRecords; return apiTestCaseRecords;
} }
public 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(apiTestCaseService.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()));

View File

@ -24,6 +24,7 @@ import io.metersphere.sdk.util.SubListUtils;
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.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -33,6 +34,7 @@ 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;
@ -78,7 +80,7 @@ public class ApiScenarioBatchRunService {
*/ */
private void batchRun(ApiScenarioBatchRunRequest request, String userId) { private void batchRun(ApiScenarioBatchRunRequest request, String userId) {
try { try {
if (StringUtils.equals(request.getRunModeConfig().getRunMode(), ApiBatchRunMode.PARALLEL.name())) { if (isParallel(request.getRunModeConfig().getRunMode())) {
parallelExecute(request, userId); parallelExecute(request, userId);
} else { } else {
serialExecute(request, userId); serialExecute(request, userId);
@ -88,6 +90,10 @@ public class ApiScenarioBatchRunService {
} }
} }
private boolean isParallel(String runMode) {
return StringUtils.equals(runMode, ApiBatchRunMode.PARALLEL.name());
}
/** /**
* 串行批量执行 * 串行批量执行
* *
@ -149,42 +155,32 @@ public class ApiScenarioBatchRunService {
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<>();
Boolean isIntegratedReport = runModeConfig.isIntegratedReport();
AtomicInteger sort = new AtomicInteger(1);
List<ApiScenarioReportStep> apiScenarioReportSteps = new ArrayList<>(ids.size());
List<ApiScenario> apiScenarios = new ArrayList<>(ids.size()); List<ApiScenario> apiScenarios = new ArrayList<>(ids.size());
// 分批查询 // 分批查询
SubListUtils.dealForSubList(ids, 100, subIds -> apiScenarios.addAll(extApiScenarioMapper.getScenarioExecuteInfoByIds(subIds))); List<ApiScenario> finalApiScenarios = apiScenarios;
SubListUtils.dealForSubList(ids, 100, subIds -> finalApiScenarios.addAll(extApiScenarioMapper.getScenarioExecuteInfoByIds(subIds)));
Map<String, ApiScenario> apiScenarioMap = apiScenarios.stream() Map<String, ApiScenario> apiScenarioMap = apiScenarios.stream()
.collect(Collectors.toMap(ApiScenario::getId, Function.identity())); .collect(Collectors.toMap(ApiScenario::getId, Function.identity()));
apiScenarios = new ArrayList<>(ids.size());
// 这里ID顺序和队列的ID顺序保持一致
for (String id : ids) { for (String id : ids) {
// 按照ID顺序排序
ApiScenario apiScenario = apiScenarioMap.get(id); ApiScenario apiScenario = apiScenarioMap.get(id);
if (apiScenario == null) { if (apiScenario == null) {
break; break;
} }
apiScenarios.add(apiScenario);
if (runModeConfig.isIntegratedReport()) {
// 集合报告初始化一级步骤
ApiScenarioReportStep apiScenarioReportStep = getApiScenarioReportStep(apiScenario, runModeConfig.getCollectionReport().getReportId(), sort.getAndIncrement());
apiScenarioReportSteps.add(apiScenarioReportStep);
} else {
// 非集合报告初始化独立报告执行时初始化步骤
String reportId = initScenarioReport(runModeConfig, apiScenario, userId).getApiScenarioReportId();
scenarioReportMap.put(id, reportId);
}
} }
if (CollectionUtils.isNotEmpty(apiScenarioReportSteps)) { if (runModeConfig.isIntegratedReport()) {
apiScenarioReportService.insertApiScenarioReportStep(apiScenarioReportSteps); // 集合报告初始化一级步骤
initApiScenarioReportStep(apiScenarios, runModeConfig.getCollectionReport().getReportId());
return null;
} else {
// 非集合报告初始化独立报告执行时初始化步骤
return initScenarioReport(runModeConfig, apiScenarios, userId);
} }
return isIntegratedReport ? null : scenarioReportMap;
} }
@ -199,14 +195,21 @@ public class ApiScenarioBatchRunService {
} }
} }
private ApiScenarioReportStep getApiScenarioReportStep(ApiScenario apiScenario, String reportId, long sort) { public void initApiScenarioReportStep(List<ApiScenario> apiScenarios, String reportId) {
ApiScenarioReportStep apiReportStep = new ApiScenarioReportStep(); AtomicLong sort = new AtomicLong(1);
apiReportStep.setReportId(reportId); List<ApiScenarioReportStep> apiScenarioReportSteps = new ArrayList<>(apiScenarios.size());
apiReportStep.setStepId(apiScenario.getId()); for (ApiScenario apiScenario : apiScenarios) {
apiReportStep.setSort(sort); ApiScenarioReportStep apiReportStep = new ApiScenarioReportStep();
apiReportStep.setName(apiScenario.getName()); apiReportStep.setReportId(reportId);
apiReportStep.setStepType(ApiExecuteResourceType.API_SCENARIO.name()); apiReportStep.setStepId(apiScenario.getId());
return apiReportStep; apiReportStep.setSort(sort.getAndIncrement());
apiReportStep.setName(apiScenario.getName());
apiReportStep.setStepType(ApiExecuteResourceType.API_SCENARIO.name());
apiScenarioReportSteps.add(apiReportStep);
}
if (CollectionUtils.isNotEmpty(apiScenarioReportSteps)) {
apiScenarioReportService.insertApiScenarioReportStep(apiScenarioReportSteps);
}
} }
private ApiRunModeConfigDTO getRunModeConfig(ApiScenarioBatchRunRequest request) { private ApiRunModeConfigDTO getRunModeConfig(ApiScenarioBatchRunRequest request) {
@ -289,13 +292,25 @@ public class ApiScenarioBatchRunService {
return taskRequest; return taskRequest;
} }
private TaskInfo getTaskInfo(String projectId, ApiRunModeConfigDTO runModeConfig) { public TaskInfo getTaskInfo(String projectId, ApiRunModeConfigDTO runModeConfig) {
TaskInfo taskInfo = apiScenarioRunService.getTaskInfo(projectId, ApiExecuteRunMode.RUN.name()); TaskInfo taskInfo = apiScenarioRunService.getTaskInfo(projectId, ApiExecuteRunMode.RUN.name());
taskInfo.setSaveResult(true); return apiBatchRunBaseService.setBatchRunTaskInfoParam(runModeConfig, taskInfo);
taskInfo.setRealTime(false); }
taskInfo.setNeedParseScript(true);
taskInfo.setRunModeConfig(runModeConfig); public Map<String, String> initScenarioReport(ApiRunModeConfigDTO runModeConfig, List<ApiScenario> apiScenarios, String userId) {
return taskInfo; List<ApiScenarioReport> apiScenarioReports = new ArrayList<>(apiScenarios.size());
List<ApiScenarioRecord> apiScenarioRecords = new ArrayList<>(apiScenarios.size());
for (ApiScenario apiScenario : apiScenarios) {
// 初始化报告
ApiScenarioReport apiScenarioReport = getScenarioReport(runModeConfig, apiScenario, userId);
apiScenarioReport.setId(IDGenerator.nextStr());
apiScenarioReports.add(apiScenarioReport);
// 创建报告和用例的关联关系
ApiScenarioRecord apiScenarioRecord = apiScenarioRunService.getApiScenarioRecord(apiScenario, apiScenarioReport);
apiScenarioRecords.add(apiScenarioRecord);
}
apiScenarioReportService.insertApiScenarioReport(apiScenarioReports, apiScenarioRecords);
return apiScenarioRecords.stream().collect(Collectors.toMap(ApiScenarioRecord::getApiScenarioId, ApiScenarioRecord::getApiScenarioReportId));
} }
/** /**
@ -335,9 +350,11 @@ public class ApiScenarioBatchRunService {
} }
public void updateStopOnFailureReport(ExecutionQueue queue) { public void updateStopOnFailureReport(ExecutionQueue queue) {
ApiRunModeConfigDTO runModeConfig = queue.getRunModeConfig(); ApiRunModeConfigDTO runModeConfig = queue.getRunModeConfig();
if (BooleanUtils.isFalse(runModeConfig.isIntegratedReport())) {
return;
}
try { try {
ExecutionQueueDetail queueDetail = apiExecutionQueueService.getNextDetail(queue.getQueueId()); ExecutionQueueDetail queueDetail = apiExecutionQueueService.getNextDetail(queue.getQueueId());
if (queueDetail == null) { if (queueDetail == null) {
@ -361,19 +378,18 @@ public class ApiScenarioBatchRunService {
queueDetail = apiExecutionQueueService.getNextDetail(queue.getQueueId()); queueDetail = apiExecutionQueueService.getNextDetail(queue.getQueueId());
} }
if (runModeConfig.isIntegratedReport()) {
// 获取未执行的请求数更新统计指标 // 获取未执行的请求数更新统计指标
String reportId = runModeConfig.getCollectionReport().getReportId(); String reportId = runModeConfig.getCollectionReport().getReportId();
ApiScenarioReport report = apiScenarioReportMapper.selectByPrimaryKey(reportId); ApiScenarioReport report = apiScenarioReportMapper.selectByPrimaryKey(reportId);
Long pendingCount = requestCount + report.getPendingCount(); Long pendingCount = requestCount + report.getPendingCount();
report.setPendingCount(pendingCount); report.setPendingCount(pendingCount);
// 计算各种通过率 // 计算各种通过率
long total = apiScenarioReportService.getRequestTotal(report); long total = apiScenarioReportService.getRequestTotal(report);
report = apiBatchRunBaseService.computeRequestRate(report, total); report = apiBatchRunBaseService.computeRequestRate(report, total);
report.setStatus(ReportStatus.ERROR.name()); report.setStatus(ReportStatus.ERROR.name());
report.setExecStatus(ExecStatus.COMPLETED.name()); report.setExecStatus(ExecStatus.COMPLETED.name());
apiScenarioReportMapper.updateByPrimaryKeySelective(report); apiScenarioReportMapper.updateByPrimaryKeySelective(report);
}
} catch (Exception e) { } catch (Exception e) {
LogUtils.error("失败停止,补充报告步骤失败:", e); LogUtils.error("失败停止,补充报告步骤失败:", e);
} }

View File

@ -1197,9 +1197,10 @@ public class ApiScenarioControllerTests extends BaseTest {
requestGetPermissionTest(PermissionConstants.PROJECT_API_SCENARIO_EXECUTE, RUN_REAL_TIME, addApiScenario.getId(), "reportId"); requestGetPermissionTest(PermissionConstants.PROJECT_API_SCENARIO_EXECUTE, RUN_REAL_TIME, addApiScenario.getId(), "reportId");
} }
@Test
@Order(6) @Order(6)
public void batchRun() throws Exception { public void batchRun() throws Exception {
mockPost("/api/run", ""); mockPost("/api/batch/run", "");
ApiScenarioBatchRunRequest request = new ApiScenarioBatchRunRequest(); ApiScenarioBatchRunRequest request = new ApiScenarioBatchRunRequest();
List<String> ids = new ArrayList<>(); List<String> ids = new ArrayList<>();

View File

@ -6,6 +6,7 @@ import io.metersphere.plan.constants.TestPlanResourceConfig;
import io.metersphere.plan.dto.request.*; import io.metersphere.plan.dto.request.*;
import io.metersphere.plan.dto.response.TestPlanApiCasePageResponse; import io.metersphere.plan.dto.response.TestPlanApiCasePageResponse;
import io.metersphere.plan.dto.response.TestPlanAssociationResponse; import io.metersphere.plan.dto.response.TestPlanAssociationResponse;
import io.metersphere.plan.service.TestPlanApiCaseBatchRunService;
import io.metersphere.plan.dto.response.TestPlanOperationResponse; import io.metersphere.plan.dto.response.TestPlanOperationResponse;
import io.metersphere.plan.service.TestPlanApiCaseLogService; import io.metersphere.plan.service.TestPlanApiCaseLogService;
import io.metersphere.plan.service.TestPlanApiCaseService; import io.metersphere.plan.service.TestPlanApiCaseService;
@ -43,6 +44,8 @@ public class TestPlanApiCaseController {
@Resource @Resource
private TestPlanApiCaseService testPlanApiCaseService; private TestPlanApiCaseService testPlanApiCaseService;
@Resource @Resource
private TestPlanApiCaseBatchRunService testPlanApiCaseBatchRunService;
@Resource
private TestPlanManagementService testPlanManagementService; private TestPlanManagementService testPlanManagementService;
@Resource @Resource
private TestPlanService testPlanService; private TestPlanService testPlanService;
@ -128,5 +131,13 @@ public class TestPlanApiCaseController {
} }
@PostMapping("/batch/run")
@Operation(summary = "批量执行")
@RequiresPermissions(PermissionConstants.TEST_PLAN_READ_EXECUTE)
// @CheckOwner(resourceId = "#request.getId()", resourceType = "test_plan_api_case") todo
public void batchRun(@Validated @RequestBody TestPlanApiCaseBatchRunRequest request) {
testPlanApiCaseBatchRunService.asyncBatchRun(request, SessionUtils.getUserId());
}
//TODO 批量移动 计划集内 //TODO 批量移动 计划集内
} }

View File

@ -7,6 +7,10 @@ import io.metersphere.plan.dto.request.TestPlanApiScenarioModuleRequest;
import io.metersphere.plan.dto.request.TestPlanApiScenarioRequest; import io.metersphere.plan.dto.request.TestPlanApiScenarioRequest;
import io.metersphere.plan.dto.request.TestPlanApiScenarioTreeRequest; import io.metersphere.plan.dto.request.TestPlanApiScenarioTreeRequest;
import io.metersphere.plan.dto.response.TestPlanApiScenarioPageResponse; import io.metersphere.plan.dto.response.TestPlanApiScenarioPageResponse;
import io.metersphere.plan.dto.request.TestPlanApiCaseBatchRunRequest;
import io.metersphere.plan.dto.request.TestPlanApiScenarioBatchRunRequest;
import io.metersphere.plan.service.TestPlanApiCaseBatchRunService;
import io.metersphere.plan.service.TestPlanApiScenarioBatchRunService;
import io.metersphere.plan.service.TestPlanApiScenarioService; import io.metersphere.plan.service.TestPlanApiScenarioService;
import io.metersphere.sdk.constants.PermissionConstants; import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.dto.api.task.TaskRequestDTO; import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
@ -33,15 +37,8 @@ public class TestPlanApiScenarioController {
@Resource @Resource
private TestPlanApiScenarioService testPlanApiScenarioService; private TestPlanApiScenarioService testPlanApiScenarioService;
@Resource
@GetMapping("/run/{id}") private TestPlanApiScenarioBatchRunService testPlanApiScenarioBatchRunService;
@Operation(summary = "接口测试-接口场景管理-场景执行")
@RequiresPermissions(PermissionConstants.TEST_PLAN_READ_EXECUTE)
// @CheckOwner(resourceId = "#id", resourceType = "test_plan_api_scenario")
public TaskRequestDTO run(@PathVariable String id, @RequestParam(required = false) String reportId) {
return testPlanApiScenarioService.run(id, reportId, SessionUtils.getUserId());
}
@PostMapping("/page") @PostMapping("/page")
@Operation(summary = "测试计划-已关联场景用例列表分页查询") @Operation(summary = "测试计划-已关联场景用例列表分页查询")
@ -68,4 +65,20 @@ public class TestPlanApiScenarioController {
public List<BaseTreeNode> getTree(@Validated @RequestBody TestPlanApiScenarioTreeRequest request) { public List<BaseTreeNode> getTree(@Validated @RequestBody TestPlanApiScenarioTreeRequest request) {
return testPlanApiScenarioService.getTree(request); return testPlanApiScenarioService.getTree(request);
} }
@GetMapping("/run/{id}")
@Operation(summary = "接口测试-接口场景管理-场景执行")
@RequiresPermissions(PermissionConstants.TEST_PLAN_READ_EXECUTE)
// @CheckOwner(resourceId = "#id", resourceType = "test_plan_api_scenario")
public TaskRequestDTO run(@PathVariable String id, @RequestParam(required = false) String reportId) {
return testPlanApiScenarioService.run(id, reportId, SessionUtils.getUserId());
}
@PostMapping("/batch/run")
@Operation(summary = "批量执行")
@RequiresPermissions(PermissionConstants.TEST_PLAN_READ_EXECUTE)
// @CheckOwner(resourceId = "#request.getId()", resourceType = "test_plan_api_case") todo
public void batchRun(@Validated @RequestBody TestPlanApiScenarioBatchRunRequest request) {
testPlanApiScenarioBatchRunService.asyncBatchRun(request, SessionUtils.getUserId());
}
} }

View File

@ -0,0 +1,16 @@
package io.metersphere.plan.dto.request;
import io.metersphere.api.dto.ApiRunModeRequest;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
@Data
@EqualsAndHashCode(callSuper = false)
public class TestPlanApiCaseBatchRunRequest extends TestPlanApiCaseBatchRequest implements Serializable {
private static final long serialVersionUID = 1L;
private ApiRunModeRequest runModeConfig;
}

View File

@ -0,0 +1,20 @@
package io.metersphere.plan.dto.request;
import io.metersphere.api.dto.ApiRunModeRequest;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
@Data
@EqualsAndHashCode(callSuper = false)
public class TestPlanApiScenarioBatchRunRequest extends BasePlanCaseBatchRequest implements Serializable {
private static final long serialVersionUID = 1L;
@Valid
@Schema(description = "运行模式配置")
private ApiRunModeRequest runModeConfig;
}

View File

@ -65,4 +65,6 @@ public interface ExtTestPlanApiCaseMapper {
* @return 计划功能用例集合 * @return 计划功能用例集合
*/ */
List<TestPlanApiCase> getPlanApiCaseByIds(@Param("planIds") List<String> planIds); List<TestPlanApiCase> getPlanApiCaseByIds(@Param("planIds") List<String> planIds);
List<TestPlanApiCase> getApiCaseExecuteInfoByIds(@Param("ids") List<String> ids);
} }

View File

@ -670,4 +670,13 @@
</if> </if>
</where> </where>
</select> </select>
<select id="getApiCaseExecuteInfoByIds" resultType="io.metersphere.plan.domain.TestPlanApiCase">
select id, test_plan_id, api_case_id, environment_id
from test_plan_api_case
where id in
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
</mapper> </mapper>

View File

@ -55,4 +55,6 @@ public interface ExtTestPlanApiScenarioMapper {
* @return 计划功能用例集合 * @return 计划功能用例集合
*/ */
List<TestPlanApiScenario> getPlanApiScenarioByIds(@Param("planIds") List<String> planIds); List<TestPlanApiScenario> getPlanApiScenarioByIds(@Param("planIds") List<String> planIds);
List<TestPlanApiScenario> getScenarioExecuteInfoByIds(@Param("ids") List<String> ids);
} }

View File

@ -386,4 +386,13 @@
</if> </if>
</where> </where>
</select> </select>
<select id="getScenarioExecuteInfoByIds" resultType="io.metersphere.plan.domain.TestPlanApiScenario">
SELECT id, test_plan_id, api_scenario_id, environment_id
FROM test_plan_api_scenario
WHERE id IN
<foreach collection="ids" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</select>
</mapper> </mapper>

View File

@ -0,0 +1,271 @@
package io.metersphere.plan.service;
import io.metersphere.api.domain.ApiReport;
import io.metersphere.api.domain.ApiReportStep;
import io.metersphere.api.domain.ApiTestCase;
import io.metersphere.api.domain.ApiTestCaseRecord;
import io.metersphere.api.mapper.ApiTestCaseMapper;
import io.metersphere.api.mapper.ExtApiTestCaseMapper;
import io.metersphere.api.service.ApiBatchRunBaseService;
import io.metersphere.api.service.ApiExecuteService;
import io.metersphere.api.service.definition.ApiReportService;
import io.metersphere.api.service.definition.ApiTestCaseBatchRunService;
import io.metersphere.api.service.definition.ApiTestCaseService;
import io.metersphere.api.service.queue.ApiExecutionQueueService;
import io.metersphere.plan.domain.TestPlan;
import io.metersphere.plan.domain.TestPlanApiCase;
import io.metersphere.plan.dto.request.TestPlanApiCaseBatchRunRequest;
import io.metersphere.plan.mapper.ExtTestPlanApiCaseMapper;
import io.metersphere.plan.mapper.TestPlanApiCaseMapper;
import io.metersphere.plan.mapper.TestPlanMapper;
import io.metersphere.sdk.constants.ApiBatchRunMode;
import io.metersphere.sdk.constants.ApiExecuteResourceType;
import io.metersphere.sdk.dto.api.task.*;
import io.metersphere.sdk.dto.queue.ExecutionQueue;
import io.metersphere.sdk.dto.queue.ExecutionQueueDetail;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.LogUtils;
import io.metersphere.sdk.util.SubListUtils;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
@Service
@Transactional(rollbackFor = Exception.class)
public class TestPlanApiCaseBatchRunService {
@Resource
private ApiTestCaseMapper apiTestCaseMapper;
@Resource
private TestPlanApiCaseMapper testPlanApiCaseMapper;
@Resource
private ExtApiTestCaseMapper extApiTestCaseMapper;
@Resource
private ExtTestPlanApiCaseMapper extTestPlanApiCaseMapper;
@Resource
private TestPlanApiCaseService testPlanApiCaseService;
@Resource
private ApiExecuteService apiExecuteService;
@Resource
private ApiExecutionQueueService apiExecutionQueueService;
@Resource
private ApiReportService apiReportService;
@Resource
private ApiTestCaseBatchRunService apiTestCaseBatchRunService;
@Resource
private ApiBatchRunBaseService apiBatchRunBaseService;
@Resource
private ApiTestCaseService apiTestCaseService;
@Resource
private TestPlanMapper testPlanMapper;
/**
* 异步批量执行
*
* @param request
* @param userId
*/
public void asyncBatchRun(TestPlanApiCaseBatchRunRequest request, String userId) {
Thread.startVirtualThread(() -> batchRun(request, userId));
}
/**
* 批量执行
*
* @param request
* @param userId
*/
private void batchRun(TestPlanApiCaseBatchRunRequest request, String userId) {
try {
if (StringUtils.equals(request.getRunModeConfig().getRunMode(), ApiBatchRunMode.PARALLEL.name())) {
parallelExecute(request, userId);
} else {
serialExecute(request, userId);
}
} catch (Exception e) {
LogUtils.error("批量执行用例失败: ", e);
}
}
/**
* 串行批量执行
*
* @param request
*/
public void serialExecute(TestPlanApiCaseBatchRunRequest request, String userId) throws Exception {
List<String> ids = testPlanApiCaseService.doSelectIds(request);
// todo 查询测试规划
ApiRunModeConfigDTO runModeConfig = getRunModeConfig(request);
// 先初始化集成报告设置好报告ID再初始化执行队列
ExecutionQueue queue = apiBatchRunBaseService.initExecutionqueue(ids, runModeConfig, ApiExecuteResourceType.API_CASE.name(), userId);
// 执行第一个任务
ExecutionQueueDetail nextDetail = apiExecutionQueueService.getNextDetail(queue.getQueueId());
executeNextTask(queue, nextDetail);
}
/**
* 并行批量执行
*
* @param request
*/
public void parallelExecute(TestPlanApiCaseBatchRunRequest request, String userId) {
List<String> ids = testPlanApiCaseService.doSelectIds(request);
// todo 查询测试规划
ApiRunModeConfigDTO runModeConfig = getRunModeConfig(request);
List<TestPlanApiCase> testPlanApiCases = new ArrayList<>(ids.size());
List<ApiTestCase> apiTestCases = new ArrayList<>(ids.size());
// 分批查询
SubListUtils.dealForSubList(ids, 100, subIds -> testPlanApiCases.addAll(extTestPlanApiCaseMapper.getApiCaseExecuteInfoByIds(subIds)));
List<String> caseIds = testPlanApiCases.stream()
.map(TestPlanApiCase::getApiCaseId).collect(Collectors.toList());
// 分批查询
SubListUtils.dealForSubList(caseIds, 100, subIds -> apiTestCases.addAll(extApiTestCaseMapper.getApiCaseExecuteInfoByIds(subIds)));
Map<String, ApiTestCase> apiCaseMap = apiTestCases.stream()
.collect(Collectors.toMap(ApiTestCase::getId, Function.identity()));
// 初始化报告返回用例和报告的 map
Map<String, String> caseReportMap = initParallelReport(runModeConfig, testPlanApiCases, apiCaseMap, userId);
List<TaskItem> taskItems = new ArrayList<>(ids.size());
// 这里ID顺序和队列的ID顺序保持一致
for (String id : ids) {
String reportId = caseReportMap.get(id);
TaskItem taskItem = apiExecuteService.getTaskItem(reportId, id);
taskItem.setRequestCount(1L);
taskItems.add(taskItem);
}
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(request.getTestPlanId());
TaskBatchRequestDTO taskRequest = getTaskBatchRequestDTO(testPlan.getProjectId(), runModeConfig);
taskRequest.setTaskItems(taskItems);
apiExecuteService.batchExecute(taskRequest);
}
private Map<String, String> initParallelReport(ApiRunModeConfigDTO runModeConfig, List<TestPlanApiCase> testPlanApiCases, Map<String, ApiTestCase> caseMap, String userId) {
// 初始化非集成报告
List<ApiTestCaseRecord> apiTestCaseRecords = initApiReport(runModeConfig, testPlanApiCases, caseMap, userId);
return apiTestCaseRecords.stream()
.collect(Collectors.toMap(ApiTestCaseRecord::getApiTestCaseId, ApiTestCaseRecord::getApiReportId));
}
private ApiReportStep getApiReportStep(ApiTestCase apiTestCase, String reportId, long sort) {
ApiReportStep apiReportStep = new ApiReportStep();
apiReportStep.setReportId(reportId);
apiReportStep.setStepId(apiTestCase.getId());
apiReportStep.setSort(sort);
apiReportStep.setName(apiTestCase.getName());
apiReportStep.setStepType(ApiExecuteResourceType.API_CASE.name());
return apiReportStep;
}
private ApiRunModeConfigDTO getRunModeConfig(TestPlanApiCaseBatchRunRequest request) {
ApiRunModeConfigDTO runModeConfig = BeanUtils.copyBean(new ApiRunModeConfigDTO(), request.getRunModeConfig());
return runModeConfig;
}
/**
* 执行串行的下一个任务
*
* @param queue
* @param queueDetail
*/
public void executeNextTask(ExecutionQueue queue, ExecutionQueueDetail queueDetail) {
ApiRunModeConfigDTO runModeConfig = queue.getRunModeConfig();
String resourceId = queueDetail.getResourceId();
TestPlanApiCase testPlanApiCase = testPlanApiCaseMapper.selectByPrimaryKey(resourceId);
if (testPlanApiCase == null) {
LogUtils.info("当前执行任务的用例已删除 {}", resourceId);
return;
}
ApiTestCase apiTestCase = apiTestCaseMapper.selectByPrimaryKey(testPlanApiCase.getApiCaseId());
// 独立报告执行到当前任务时初始化报告
String reportId = initApiReport(runModeConfig, List.of(testPlanApiCase), Map.of(apiTestCase.getId(), apiTestCase), queue.getUserId()).get(0).getApiReportId();
TaskRequestDTO taskRequest = getTaskRequestDTO(reportId, apiTestCase, runModeConfig);
taskRequest.getTaskInfo().setQueueId(queue.getQueueId());
taskRequest.getTaskItem().setRequestCount(1L);
apiExecuteService.execute(taskRequest);
}
private TaskRequestDTO getTaskRequestDTO(String reportId, ApiTestCase apiTestCase, ApiRunModeConfigDTO runModeConfig) {
TaskRequestDTO taskRequest = new TaskRequestDTO();
TaskItem taskItem = apiExecuteService.getTaskItem(reportId, apiTestCase.getId());
TaskInfo taskInfo = getTaskInfo(apiTestCase.getProjectId(), runModeConfig);
taskRequest.setTaskInfo(taskInfo);
taskRequest.setTaskItem(taskItem);
return taskRequest;
}
private TaskBatchRequestDTO getTaskBatchRequestDTO(String projectId, ApiRunModeConfigDTO runModeConfig) {
TaskBatchRequestDTO taskRequest = new TaskBatchRequestDTO();
TaskInfo taskInfo = getTaskInfo(projectId, runModeConfig);
taskRequest.setTaskInfo(taskInfo);
return taskRequest;
}
private TaskInfo getTaskInfo(String projectId, ApiRunModeConfigDTO runModeConfig) {
TaskInfo taskInfo = apiTestCaseBatchRunService.getTaskInfo(projectId, runModeConfig);
taskInfo.setResourceType(ApiExecuteResourceType.TEST_PLAN_API_CASE.name());
return taskInfo;
}
/**
* 预生成用例的执行报告
*
* @param runModeConfig
* @return
*/
public List<ApiTestCaseRecord> initApiReport(ApiRunModeConfigDTO runModeConfig, List<TestPlanApiCase> testPlanApiCases,
Map<String, ApiTestCase> caseMap, String userId) {
List<ApiReport> apiReports = new ArrayList<>();
List<ApiTestCaseRecord> apiTestCaseRecords = new ArrayList<>();
List<ApiReportStep> apiReportSteps = new ArrayList<>();
for (TestPlanApiCase testPlanApiCase : testPlanApiCases) {
ApiTestCase apiTestCase = caseMap.get(testPlanApiCase.getApiCaseId());
// 初始化报告
ApiReport apiReport = getApiReport(runModeConfig, testPlanApiCase, apiTestCase, userId);
apiReports.add(apiReport);
// 创建报告和用例的关联关系
ApiTestCaseRecord apiTestCaseRecord = apiTestCaseService.getApiTestCaseRecord(apiTestCase, apiReport);
apiTestCaseRecords.add(apiTestCaseRecord);
apiReportSteps.add(getApiReportStep(apiTestCase, apiReport.getId(), 1));
}
apiReportService.insertApiReport(apiReports, apiTestCaseRecords);
apiReportService.insertApiReportStep(apiReportSteps);
return apiTestCaseRecords;
}
private ApiReport getApiReport(ApiRunModeConfigDTO runModeConfig, TestPlanApiCase testPlanApiCase, ApiTestCase apiTestCase, String userId) {
ApiReport apiReport = apiTestCaseBatchRunService.getApiReport(runModeConfig, apiTestCase, userId);
apiReport.setEnvironmentId(getEnvId(runModeConfig, testPlanApiCase));
apiReport.setTestPlanCaseId(testPlanApiCase.getId());
return apiReport;
}
public String getEnvId(ApiRunModeConfigDTO runModeConfig, TestPlanApiCase testPlanApiCase) {
return StringUtils.isBlank(runModeConfig.getEnvironmentId()) ? testPlanApiCase.getEnvironmentId() : runModeConfig.getEnvironmentId();
}
}

View File

@ -0,0 +1,279 @@
package io.metersphere.plan.service;
import io.metersphere.api.domain.ApiScenario;
import io.metersphere.api.domain.ApiScenarioRecord;
import io.metersphere.api.domain.ApiScenarioReport;
import io.metersphere.api.mapper.ApiScenarioMapper;
import io.metersphere.api.mapper.ExtApiScenarioMapper;
import io.metersphere.api.service.ApiBatchRunBaseService;
import io.metersphere.api.service.ApiExecuteService;
import io.metersphere.api.service.queue.ApiExecutionQueueService;
import io.metersphere.api.service.scenario.ApiScenarioBatchRunService;
import io.metersphere.api.service.scenario.ApiScenarioReportService;
import io.metersphere.api.service.scenario.ApiScenarioRunService;
import io.metersphere.plan.domain.TestPlan;
import io.metersphere.plan.domain.TestPlanApiScenario;
import io.metersphere.plan.dto.request.TestPlanApiScenarioBatchRunRequest;
import io.metersphere.plan.mapper.ExtTestPlanApiScenarioMapper;
import io.metersphere.plan.mapper.TestPlanApiScenarioMapper;
import io.metersphere.plan.mapper.TestPlanMapper;
import io.metersphere.sdk.constants.ApiBatchRunMode;
import io.metersphere.sdk.constants.ApiExecuteResourceType;
import io.metersphere.sdk.constants.TaskTriggerMode;
import io.metersphere.sdk.dto.api.task.*;
import io.metersphere.sdk.dto.queue.ExecutionQueue;
import io.metersphere.sdk.dto.queue.ExecutionQueueDetail;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.DateUtils;
import io.metersphere.sdk.util.LogUtils;
import io.metersphere.sdk.util.SubListUtils;
import io.metersphere.system.uid.IDGenerator;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
@Service
@Transactional(rollbackFor = Exception.class)
public class TestPlanApiScenarioBatchRunService {
@Resource
private TestPlanApiScenarioService testPlanApiScenarioService;
@Resource
private ApiExecuteService apiExecuteService;
@Resource
private ApiExecutionQueueService apiExecutionQueueService;
@Resource
private ApiScenarioReportService apiScenarioReportService;
@Resource
private ApiScenarioBatchRunService apiScenarioBatchRunService;
@Resource
private ApiBatchRunBaseService apiBatchRunBaseService;
@Resource
private ExtApiScenarioMapper extApiScenarioMapper;
@Resource
private ExtTestPlanApiScenarioMapper extTestPlanApiScenarioMapper;
@Resource
private ApiScenarioMapper apiScenarioMapper;
@Resource
private TestPlanApiScenarioMapper testPlanApiScenarioMapper;
@Resource
private ApiScenarioRunService apiScenarioRunService;
@Resource
private TestPlanMapper testPlanMapper;
/**
* 异步批量执行
*
* @param request
* @param userId
*/
public void asyncBatchRun(TestPlanApiScenarioBatchRunRequest request, String userId) {
Thread.startVirtualThread(() -> batchRun(request, userId));
}
/**
* 批量执行
*
* @param request
* @param userId
*/
private void batchRun(TestPlanApiScenarioBatchRunRequest request, String userId) {
try {
if (StringUtils.equals(request.getRunModeConfig().getRunMode(), ApiBatchRunMode.PARALLEL.name())) {
parallelExecute(request, userId);
} else {
serialExecute(request, userId);
}
} catch (Exception e) {
LogUtils.error("批量执行用例失败: ", e);
}
}
/**
* 串行批量执行
*
* @param request
*/
public void serialExecute(TestPlanApiScenarioBatchRunRequest request, String userId) throws Exception {
// List<String> ids = testPlanApiScenarioService.doSelectIds(request, false); //todo
List<String> ids = request.getSelectIds();
// todo 查询测试规划
ApiRunModeConfigDTO runModeConfig = getRunModeConfig(request);
// 先初始化集成报告设置好报告ID再初始化执行队列
ExecutionQueue queue = apiBatchRunBaseService.initExecutionqueue(ids, runModeConfig, ApiExecuteResourceType.TEST_PLAN_API_SCENARIO.name(), userId);
// 执行第一个任务
ExecutionQueueDetail nextDetail = apiExecutionQueueService.getNextDetail(queue.getQueueId());
executeNextTask(queue, nextDetail);
}
/**
* 并行批量执行
*
* @param request
*/
public void parallelExecute(TestPlanApiScenarioBatchRunRequest request, String userId) {
// List<String> ids = testPlanApiScenarioService.doSelectIds(request, false); //todo
List<String> ids = request.getSelectIds();
// todo 查询测试规划
ApiRunModeConfigDTO runModeConfig = getRunModeConfig(request);
Map<String, String> scenarioReportMap = initReport(ids, runModeConfig, userId);
List<TaskItem> taskItems = ids.stream()
.map(id -> apiExecuteService.getTaskItem(scenarioReportMap.get(id), id)).toList();
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(request.getTestPlanId());
TaskBatchRequestDTO taskRequest = getTaskBatchRequestDTO(testPlan.getProjectId(), runModeConfig);
taskRequest.setTaskItems(taskItems);
apiExecuteService.batchExecute(taskRequest);
}
private ApiRunModeConfigDTO getRunModeConfig(TestPlanApiScenarioBatchRunRequest request) {
ApiRunModeConfigDTO runModeConfig = BeanUtils.copyBean(new ApiRunModeConfigDTO(), request.getRunModeConfig());
return runModeConfig;
}
private Map<String, String> initReport(List<String> ids, ApiRunModeConfigDTO runModeConfig, String userId) {
List<TestPlanApiScenario> testPlanApiScenarios = new ArrayList<>(ids.size());
List<ApiScenario> apiScenarios = new ArrayList<>(ids.size());
// 分批查询
List<TestPlanApiScenario> finalTestPlanApiScenarios = testPlanApiScenarios;
SubListUtils.dealForSubList(ids, 100, subIds -> finalTestPlanApiScenarios.addAll(extTestPlanApiScenarioMapper.getScenarioExecuteInfoByIds(subIds)));
List<String> caseIds = testPlanApiScenarios.stream().map(TestPlanApiScenario::getApiScenarioId).toList();
List<ApiScenario> finalApiScenarios = apiScenarios;
SubListUtils.dealForSubList(caseIds, 100, subIds -> finalApiScenarios.addAll(extApiScenarioMapper.getScenarioExecuteInfoByIds(subIds)));
Map<String, ApiScenario> apiScenarioMap = apiScenarios.stream()
.collect(Collectors.toMap(ApiScenario::getId, Function.identity()));
Map<String, TestPlanApiScenario> testPlanApiScenarioMap = testPlanApiScenarios.stream()
.collect(Collectors.toMap(TestPlanApiScenario::getId, Function.identity()));
testPlanApiScenarios = new ArrayList<>(ids.size());
for (String id : ids) {
// 按照ID顺序排序
TestPlanApiScenario testPlanApiScenario = testPlanApiScenarioMap.get(id);
if (testPlanApiScenario == null) {
break;
}
testPlanApiScenarios.add(testPlanApiScenario);
}
// 初始化独立报告执行时初始化步骤
return initScenarioReport(runModeConfig, testPlanApiScenarios, apiScenarioMap, userId);
}
public Map<String, String> initScenarioReport(ApiRunModeConfigDTO runModeConfig, List<TestPlanApiScenario> testPlanApiScenarios,
Map<String, ApiScenario> apiScenarioMap, String userId) {
List<ApiScenarioReport> apiScenarioReports = new ArrayList<>(testPlanApiScenarios.size());
List<ApiScenarioRecord> apiScenarioRecords = new ArrayList<>(testPlanApiScenarios.size());
for (TestPlanApiScenario testPlanApiScenario : testPlanApiScenarios) {
ApiScenario apiScenario = apiScenarioMap.get(testPlanApiScenario.getApiScenarioId());
// 初始化报告
ApiScenarioReport apiScenarioReport = getScenarioReport(runModeConfig, testPlanApiScenario, apiScenario, userId);
apiScenarioReport.setId(IDGenerator.nextStr());
apiScenarioReports.add(apiScenarioReport);
// 创建报告和用例的关联关系
ApiScenarioRecord apiScenarioRecord = apiScenarioRunService.getApiScenarioRecord(apiScenario, apiScenarioReport);
apiScenarioRecords.add(apiScenarioRecord);
}
apiScenarioReportService.insertApiScenarioReport(apiScenarioReports, apiScenarioRecords);
return apiScenarioRecords.stream().collect(Collectors.toMap(ApiScenarioRecord::getApiScenarioId, ApiScenarioRecord::getApiScenarioReportId));
}
/**
* 执行串行的下一个任务
*
* @param queue
* @param queueDetail
*/
public void executeNextTask(ExecutionQueue queue, ExecutionQueueDetail queueDetail) {
ApiRunModeConfigDTO runModeConfig = queue.getRunModeConfig();
TestPlanApiScenario testPlanApiScenario = testPlanApiScenarioMapper.selectByPrimaryKey(queueDetail.getResourceId());
ApiScenario apiScenario = apiScenarioMapper.selectByPrimaryKey(testPlanApiScenario.getApiScenarioId());
// 独立报告执行到当前任务时初始化报告
String reportId = initScenarioReport(runModeConfig, testPlanApiScenario, apiScenario, queue.getUserId()).getApiScenarioReportId();
TaskRequestDTO taskRequest = getTaskRequestDTO(apiScenario.getProjectId(), queue.getRunModeConfig());
TaskItem taskItem = apiExecuteService.getTaskItem(reportId, queueDetail.getResourceId());
taskRequest.setTaskItem(taskItem);
taskRequest.getTaskInfo().setQueueId(queue.getQueueId());
apiExecuteService.execute(taskRequest);
}
private TaskRequestDTO getTaskRequestDTO(String projectId, ApiRunModeConfigDTO runModeConfig) {
TaskRequestDTO taskRequest = new TaskRequestDTO();
TaskInfo taskInfo = getTaskInfo(projectId, runModeConfig);
taskRequest.setTaskInfo(taskInfo);
return taskRequest;
}
private TaskBatchRequestDTO getTaskBatchRequestDTO(String projectId, ApiRunModeConfigDTO runModeConfig) {
TaskBatchRequestDTO taskRequest = new TaskBatchRequestDTO();
TaskInfo taskInfo = getTaskInfo(projectId, runModeConfig);
taskRequest.setTaskInfo(taskInfo);
return taskRequest;
}
private TaskInfo getTaskInfo(String projectId, ApiRunModeConfigDTO runModeConfig) {
TaskInfo taskInfo = apiScenarioBatchRunService.getTaskInfo(projectId, runModeConfig);
taskInfo.setResourceType(ApiExecuteResourceType.TEST_PLAN_API_SCENARIO.name());
return taskInfo;
}
/**
* 预生成用例的执行报告
*
* @param runModeConfig
* @param apiScenario
* @return
*/
public ApiScenarioRecord initScenarioReport(ApiRunModeConfigDTO runModeConfig, TestPlanApiScenario testPlanApiScenario,
ApiScenario apiScenario, String userId) {
// 初始化报告
ApiScenarioReport apiScenarioReport = getScenarioReport(runModeConfig, testPlanApiScenario, apiScenario, userId);
apiScenarioReport.setId(IDGenerator.nextStr());
// 创建报告和用例的关联关系
ApiScenarioRecord apiScenarioRecord = apiScenarioRunService.getApiScenarioRecord(apiScenario, apiScenarioReport);
apiScenarioReportService.insertApiScenarioReport(List.of(apiScenarioReport), List.of(apiScenarioRecord));
return apiScenarioRecord;
}
public String getEnvId(ApiRunModeConfigDTO runModeConfig, TestPlanApiScenario testPlanApiScenario) {
return StringUtils.isBlank(runModeConfig.getEnvironmentId()) ? testPlanApiScenario.getEnvironmentId() : runModeConfig.getEnvironmentId();
}
private ApiScenarioReport getScenarioReport(ApiRunModeConfigDTO runModeConfig, TestPlanApiScenario testPlanApiScenario, ApiScenario apiScenario, String userId) {
ApiScenarioReport apiScenarioReport = getScenarioReport(runModeConfig, userId);
apiScenarioReport.setEnvironmentId(apiScenarioRunService.getEnvId(runModeConfig, apiScenario));
apiScenarioReport.setName(apiScenario.getName() + "_" + DateUtils.getTimeString(System.currentTimeMillis()));
apiScenarioReport.setProjectId(apiScenario.getProjectId());
apiScenarioReport.setTriggerMode(TaskTriggerMode.BATCH.name());
apiScenarioReport.setTestPlanScenarioId(testPlanApiScenario.getId());
apiScenarioReport.setEnvironmentId(getEnvId(runModeConfig, testPlanApiScenario));
return apiScenarioReport;
}
public ApiScenarioReport getScenarioReport(ApiRunModeConfigDTO runModeConfig, String userId) {
ApiScenarioReport apiScenarioReport = apiScenarioRunService.getScenarioReport(userId);
apiScenarioReport.setEnvironmentId(runModeConfig.getEnvironmentId());
apiScenarioReport.setRunMode(runModeConfig.getRunMode());
apiScenarioReport.setPoolId(runModeConfig.getPoolId());
apiScenarioReport.setTriggerMode(TaskTriggerMode.BATCH.name());
return apiScenarioReport;
}
}

View File

@ -5,6 +5,7 @@ import io.metersphere.api.constants.ApiDefinitionStatus;
import io.metersphere.api.controller.result.ApiResultCode; import io.metersphere.api.controller.result.ApiResultCode;
import io.metersphere.api.domain.ApiDefinition; import io.metersphere.api.domain.ApiDefinition;
import io.metersphere.api.domain.ApiTestCase; import io.metersphere.api.domain.ApiTestCase;
import io.metersphere.api.dto.ApiRunModeRequest;
import io.metersphere.api.dto.definition.ApiDefinitionAddRequest; import io.metersphere.api.dto.definition.ApiDefinitionAddRequest;
import io.metersphere.api.dto.definition.ApiTestCaseAddRequest; import io.metersphere.api.dto.definition.ApiTestCaseAddRequest;
import io.metersphere.api.dto.request.http.MsHTTPElement; import io.metersphere.api.dto.request.http.MsHTTPElement;
@ -21,6 +22,7 @@ import io.metersphere.plan.dto.response.TestPlanOperationResponse;
import io.metersphere.plan.mapper.TestPlanApiCaseMapper; import io.metersphere.plan.mapper.TestPlanApiCaseMapper;
import io.metersphere.plan.service.TestPlanApiCaseService; import io.metersphere.plan.service.TestPlanApiCaseService;
import io.metersphere.project.mapper.ExtBaseProjectVersionMapper; import io.metersphere.project.mapper.ExtBaseProjectVersionMapper;
import io.metersphere.sdk.constants.ApiBatchRunMode;
import io.metersphere.sdk.constants.PermissionConstants; import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.dto.api.task.GetRunScriptRequest; import io.metersphere.sdk.dto.api.task.GetRunScriptRequest;
import io.metersphere.sdk.dto.api.task.TaskItem; import io.metersphere.sdk.dto.api.task.TaskItem;
@ -56,6 +58,7 @@ public class TestPlanApiCaseControllerTests extends BaseTest {
public static final String API_CASE_BATCH_UPDATE_EXECUTOR_URL = "batch/update/executor"; public static final String API_CASE_BATCH_UPDATE_EXECUTOR_URL = "batch/update/executor";
private static final String URL_POST_RESOURCE_API_CASE_SORT = "/sort"; private static final String URL_POST_RESOURCE_API_CASE_SORT = "/sort";
public static final String RUN = "run/{0}"; public static final String RUN = "run/{0}";
public static final String BATCH_RUN = "batch/run";
public static final String RUN_WITH_REPORT_ID = "run/{0}?reportId={1}"; public static final String RUN_WITH_REPORT_ID = "run/{0}?reportId={1}";
@Resource @Resource
@ -274,6 +277,35 @@ public class TestPlanApiCaseControllerTests extends BaseTest {
requestGetPermissionTest(PermissionConstants.TEST_PLAN_READ_EXECUTE, RUN, testPlanApiCase.getId()); requestGetPermissionTest(PermissionConstants.TEST_PLAN_READ_EXECUTE, RUN, testPlanApiCase.getId());
} }
@Test
@Order(7)
public void batchRun() throws Exception {
TestPlanApiCaseBatchRunRequest request = new TestPlanApiCaseBatchRunRequest();
request.setSelectIds(List.of(testPlanApiCase.getId()));
request.setTestPlanId(testPlanApiCase.getTestPlanId());
ApiRunModeRequest apiRunModeRequest = new ApiRunModeRequest();
apiRunModeRequest.setRunMode(ApiBatchRunMode.PARALLEL.name());
apiRunModeRequest.setStopOnFailure(false);
apiRunModeRequest.setPoolId("poolId");
request.setRunModeConfig(apiRunModeRequest);
this.requestPostWithOk(BATCH_RUN, request);
request.setProtocols(List.of("HTTP"));
this.requestPostWithOk(BATCH_RUN, request);
apiRunModeRequest.setIntegratedReport(false);
apiRunModeRequest.setStopOnFailure(true);
this.requestPostWithOk(BATCH_RUN, request);
apiRunModeRequest.setRunMode(ApiBatchRunMode.SERIAL.name());
this.requestPostWithOk(BATCH_RUN, request);
apiRunModeRequest.setIntegratedReport(true);
this.requestPostWithOk(BATCH_RUN, request);
// @@校验权限
requestPostPermissionTest(PermissionConstants.TEST_PLAN_READ_EXECUTE, BATCH_RUN, request);
}
public ApiTestCase initApiData() { public ApiTestCase initApiData() {
ApiDefinitionAddRequest apiDefinitionAddRequest = createApiDefinitionAddRequest(); ApiDefinitionAddRequest apiDefinitionAddRequest = createApiDefinitionAddRequest();
MsHTTPElement msHttpElement = new MsHTTPElement(); MsHTTPElement msHttpElement = new MsHTTPElement();

View File

@ -5,17 +5,16 @@ import io.metersphere.api.constants.ApiScenarioStepRefType;
import io.metersphere.api.constants.ApiScenarioStepType; import io.metersphere.api.constants.ApiScenarioStepType;
import io.metersphere.api.controller.result.ApiResultCode; import io.metersphere.api.controller.result.ApiResultCode;
import io.metersphere.api.domain.ApiScenario; import io.metersphere.api.domain.ApiScenario;
import io.metersphere.api.dto.ApiRunModeRequest;
import io.metersphere.api.dto.assertion.MsAssertionConfig; import io.metersphere.api.dto.assertion.MsAssertionConfig;
import io.metersphere.api.dto.request.http.MsHTTPElement; import io.metersphere.api.dto.request.http.MsHTTPElement;
import io.metersphere.api.dto.request.http.body.Body; import io.metersphere.api.dto.request.http.body.Body;
import io.metersphere.api.dto.request.http.body.RawBody; import io.metersphere.api.dto.request.http.body.RawBody;
import io.metersphere.api.dto.scenario.ApiScenarioAddRequest; import io.metersphere.api.dto.scenario.*;
import io.metersphere.api.dto.scenario.ApiScenarioStepRequest;
import io.metersphere.api.dto.scenario.ScenarioConfig;
import io.metersphere.api.dto.scenario.ScenarioOtherConfig;
import io.metersphere.api.service.scenario.ApiScenarioService; import io.metersphere.api.service.scenario.ApiScenarioService;
import io.metersphere.api.utils.ApiDataUtils; import io.metersphere.api.utils.ApiDataUtils;
import io.metersphere.plan.domain.TestPlanApiScenario; import io.metersphere.plan.domain.TestPlanApiScenario;
import io.metersphere.plan.dto.request.TestPlanApiScenarioBatchRunRequest;
import io.metersphere.plan.dto.request.TestPlanApiScenarioModuleRequest; import io.metersphere.plan.dto.request.TestPlanApiScenarioModuleRequest;
import io.metersphere.plan.dto.request.TestPlanApiScenarioRequest; import io.metersphere.plan.dto.request.TestPlanApiScenarioRequest;
import io.metersphere.plan.dto.request.TestPlanApiScenarioTreeRequest; import io.metersphere.plan.dto.request.TestPlanApiScenarioTreeRequest;
@ -24,7 +23,9 @@ import io.metersphere.plan.service.TestPlanApiScenarioService;
import io.metersphere.project.api.assertion.MsResponseCodeAssertion; import io.metersphere.project.api.assertion.MsResponseCodeAssertion;
import io.metersphere.project.api.assertion.MsScriptAssertion; import io.metersphere.project.api.assertion.MsScriptAssertion;
import io.metersphere.project.mapper.ExtBaseProjectVersionMapper; import io.metersphere.project.mapper.ExtBaseProjectVersionMapper;
import io.metersphere.sdk.constants.ApiBatchRunMode;
import io.metersphere.sdk.constants.MsAssertionCondition; import io.metersphere.sdk.constants.MsAssertionCondition;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.dto.api.task.GetRunScriptRequest; import io.metersphere.sdk.dto.api.task.GetRunScriptRequest;
import io.metersphere.sdk.dto.api.task.TaskItem; import io.metersphere.sdk.dto.api.task.TaskItem;
import io.metersphere.sdk.util.JSON; import io.metersphere.sdk.util.JSON;
@ -40,10 +41,7 @@ import org.springframework.test.context.jdbc.SqlConfig;
import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.MvcResult;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.HashMap; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import static io.metersphere.system.controller.handler.result.MsHttpResultCode.NOT_FOUND; import static io.metersphere.system.controller.handler.result.MsHttpResultCode.NOT_FOUND;
@ -58,6 +56,7 @@ public class TestPlanApiScenarioControllerTests extends BaseTest {
public static final String API_SCENARIO_PAGE = "page"; public static final String API_SCENARIO_PAGE = "page";
public static final String API_SCENARIO_TREE_COUNT = "module/count"; public static final String API_SCENARIO_TREE_COUNT = "module/count";
public static final String API_SCENARIO_TREE = "tree"; public static final String API_SCENARIO_TREE = "tree";
public static final String BATCH_RUN = "batch/run";
@Resource @Resource
private TestPlanApiScenarioService testPlanApiScenarioService; private TestPlanApiScenarioService testPlanApiScenarioService;
@ -105,6 +104,40 @@ public class TestPlanApiScenarioControllerTests extends BaseTest {
taskItem.setReportId("reportId"); taskItem.setReportId("reportId");
request.setTaskItem(taskItem); request.setTaskItem(taskItem);
testPlanApiScenarioService.getRunScript(request); testPlanApiScenarioService.getRunScript(request);
// @@校验权限
requestGetPermissionTest(PermissionConstants.TEST_PLAN_READ_EXECUTE, RUN, testPlanApiScenario.getId());
}
@Test
@Order(2)
public void batchRun() throws Exception {
mockPost("/api/batch/run", "");
TestPlanApiScenarioBatchRunRequest request = new TestPlanApiScenarioBatchRunRequest();
request.setSelectIds(List.of(testPlanApiScenario.getId()));
request.setTestPlanId(testPlanApiScenario.getTestPlanId());
ApiRunModeRequest apiRunModeRequest = new ApiRunModeRequest();
apiRunModeRequest.setRunMode(ApiBatchRunMode.PARALLEL.name());
apiRunModeRequest.setIntegratedReport(true);
apiRunModeRequest.setStopOnFailure(false);
apiRunModeRequest.setIntegratedReportName("aaaa");
apiRunModeRequest.setPoolId("poolId");
request.setRunModeConfig(apiRunModeRequest);
this.requestPostWithOk(BATCH_RUN, request);
apiRunModeRequest.setIntegratedReport(false);
apiRunModeRequest.setStopOnFailure(true);
this.requestPostWithOk(BATCH_RUN, request);
apiRunModeRequest.setRunMode(ApiBatchRunMode.SERIAL.name());
this.requestPostWithOk(BATCH_RUN, request);
apiRunModeRequest.setIntegratedReport(true);
this.requestPostWithOk(BATCH_RUN, request);
// @@校验权限
requestPostPermissionTest(PermissionConstants.TEST_PLAN_READ_EXECUTE, BATCH_RUN, request);
} }
public ApiScenario initApiData() { public ApiScenario initApiData() {