diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/queue/ExecutionQueue.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/queue/ExecutionQueue.java index fbe8f83644..9f128b5ae5 100644 --- a/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/queue/ExecutionQueue.java +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/queue/ExecutionQueue.java @@ -44,6 +44,11 @@ public class ExecutionQueue implements Serializable { */ private ApiRunModeConfigDTO runModeConfig; + /** + * 全部场景的请求请求总量,用于计算执行各种指标 + */ + private Long requestCount; + @Serial private static final long serialVersionUID = 1L; } \ No newline at end of file diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/queue/ExecutionQueueDetail.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/queue/ExecutionQueueDetail.java index ed733cc0fc..8dd3d25b6a 100644 --- a/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/queue/ExecutionQueueDetail.java +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/queue/ExecutionQueueDetail.java @@ -24,4 +24,9 @@ public class ExecutionQueueDetail implements Serializable { * 当前资源产生的执行报告id */ private String reportId; + + /** + * 单个场景要执行的请求总量,用于计算执行各种指标 + */ + private Long requestCount; } \ No newline at end of file diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/dto/ApiBatchRunInitReportResult.java b/backend/services/api-test/src/main/java/io/metersphere/api/dto/ApiBatchRunInitReportResult.java new file mode 100644 index 0000000000..8876556240 --- /dev/null +++ b/backend/services/api-test/src/main/java/io/metersphere/api/dto/ApiBatchRunInitReportResult.java @@ -0,0 +1,17 @@ +package io.metersphere.api.dto; + +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; + +/** + * @Author: jianxing + * @CreateTime: 2024-04-01 11:29 + */ +@Data +public class ApiBatchRunInitReportResult { + private Map scenarioReportMap = new HashMap<>(); + private Long requestCount = 0L; + private Map scenarioCountMap = new HashMap<>(); +} diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/dto/ApiFile.java b/backend/services/api-test/src/main/java/io/metersphere/api/dto/ApiFile.java index 4761acf01e..ff851dcda8 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/dto/ApiFile.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/dto/ApiFile.java @@ -1,7 +1,6 @@ package io.metersphere.api.dto; import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.Size; import lombok.Data; /** @@ -14,13 +13,11 @@ public class ApiFile { * 生成脚本时,通过 fileId + fileName(文件名) 获取文件路径 */ @NotBlank - @Size(max = 50) private String fileId; /** * 文件名 */ @NotBlank - @Size(max = 255) private String fileName; /** * 是否是本地上传的文件 @@ -30,7 +27,6 @@ public class ApiFile { * 文件别名,引用的文件需要展示别名, * 查询时,获取最新的 */ - @Size(max = 255) private String fileAlias; /** * 文件是否别删除 diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/dto/request/http/MsHTTPElement.java b/backend/services/api-test/src/main/java/io/metersphere/api/dto/request/http/MsHTTPElement.java index b626cbe090..383f03db0a 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/dto/request/http/MsHTTPElement.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/dto/request/http/MsHTTPElement.java @@ -7,7 +7,6 @@ import io.metersphere.sdk.constants.HttpMethodConstants; import io.metersphere.system.valid.EnumValue; import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.Size; import lombok.Data; import lombok.EqualsAndHashCode; @@ -24,22 +23,14 @@ import java.util.List; @EqualsAndHashCode(callSuper = true) public class MsHTTPElement extends AbstractMsProtocolTestElement { /** - * 完整请求地址 - * 自定义请求时,使用该字段 + * 接口定义和用例的请求路径,或者完整路径 */ - @Size(max = 500) - private String url; - /** - * 接口定义和用例的请求路径 - */ - @Size(max = 500) private String path; /** * 请求方法 * 取值参考:{@link HttpMethodConstants} */ @NotBlank - @Size(max = 10) @EnumValue(enumClass = HttpMethodConstants.class) private String method; /** diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/dto/request/http/body/Body.java b/backend/services/api-test/src/main/java/io/metersphere/api/dto/request/http/body/Body.java index eacc722d2a..4cc4ce8f25 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/dto/request/http/body/Body.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/dto/request/http/body/Body.java @@ -2,7 +2,6 @@ package io.metersphere.api.dto.request.http.body; import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.Size; import lombok.Data; import java.util.HashMap; @@ -21,7 +20,6 @@ public class Body { * 同时持久化多个类型的请求体 */ @NotBlank - @Size(max = 20) private String bodyType; /** * None 请求体 diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/dto/request/http/body/FormDataKV.java b/backend/services/api-test/src/main/java/io/metersphere/api/dto/request/http/body/FormDataKV.java index aef778b798..73ca427dcc 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/dto/request/http/body/FormDataKV.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/dto/request/http/body/FormDataKV.java @@ -2,7 +2,6 @@ package io.metersphere.api.dto.request.http.body; import io.metersphere.api.dto.ApiFile; import jakarta.validation.Valid; -import jakarta.validation.constraints.Size; import lombok.Data; import org.apache.commons.lang3.StringUtils; @@ -26,7 +25,6 @@ public class FormDataKV extends WWWFormKV { /** * 参数的 contentType */ - @Size(max = 100) private String contentType; public boolean isFile() { diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/dto/request/http/body/WWWFormKV.java b/backend/services/api-test/src/main/java/io/metersphere/api/dto/request/http/body/WWWFormKV.java index 8e45a69ceb..478e2b1845 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/dto/request/http/body/WWWFormKV.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/dto/request/http/body/WWWFormKV.java @@ -2,7 +2,6 @@ package io.metersphere.api.dto.request.http.body; import io.metersphere.project.api.KeyValueEnableParam; import io.metersphere.system.valid.EnumValue; -import jakarta.validation.constraints.Size; import lombok.Data; /** @@ -16,7 +15,6 @@ public class WWWFormKV extends KeyValueEnableParam { * 参数类型 * 取值参考 {@link BodyParamType} 中的 value 属性 */ - @Size(max = 20) @EnumValue(enumClass = BodyParamType.class) private String paramType = BodyParamType.STRING.getValue(); /** diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/dto/schema/JsonSchemaItem.java b/backend/services/api-test/src/main/java/io/metersphere/api/dto/schema/JsonSchemaItem.java index e00b80c366..7d4e75cb2e 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/dto/schema/JsonSchemaItem.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/dto/schema/JsonSchemaItem.java @@ -6,7 +6,6 @@ import io.metersphere.sdk.constants.ValueEnum; import io.metersphere.system.valid.EnumValue; import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -31,12 +30,10 @@ public class JsonSchemaItem { * 参数ID */ @NotBlank - @Size(max = 50) private String id; /** * 参数名称 */ - @Size(max = 200) private String title; /** * 参数类型 diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/service/ApiBatchRunBaseService.java b/backend/services/api-test/src/main/java/io/metersphere/api/service/ApiBatchRunBaseService.java index 7d76577519..add5ec3062 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/service/ApiBatchRunBaseService.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/service/ApiBatchRunBaseService.java @@ -1,5 +1,6 @@ package io.metersphere.api.service; +import io.metersphere.api.dto.ApiBatchRunInitReportResult; import io.metersphere.api.service.queue.ApiExecutionQueueService; import io.metersphere.sdk.dto.api.task.ApiRunModeConfigDTO; import io.metersphere.sdk.dto.queue.ExecutionQueue; @@ -8,10 +9,7 @@ import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.UUID; +import java.util.*; import java.util.concurrent.atomic.AtomicInteger; @Service @@ -28,6 +26,31 @@ public class ApiBatchRunBaseService { */ public ExecutionQueue initExecutionqueue(List resourceIds, ApiRunModeConfigDTO runModeConfig, String resourceType, Map caseReportMap, String userId) { ExecutionQueue queue = getExecutionQueue(runModeConfig, resourceType, userId); + List queueDetails = getExecutionQueueDetails(resourceIds, caseReportMap); + apiExecutionQueueService.insertQueue(queue, queueDetails); + return queue; + } + + /** + * 初始化执行队列 + * + * @param resourceIds + * @param runModeConfig + * @return + */ + public ExecutionQueue initExecutionqueue(List resourceIds, ApiRunModeConfigDTO runModeConfig, String resourceType, ApiBatchRunInitReportResult reportResult, String userId) { + Map scenarioCountMap = reportResult.getScenarioCountMap(); + ExecutionQueue queue = getExecutionQueue(runModeConfig, resourceType, userId); + queue.setRequestCount(reportResult.getRequestCount()); + List queueDetails = getExecutionQueueDetails(resourceIds, reportResult.getScenarioReportMap()); + for (ExecutionQueueDetail queueDetail : queueDetails) { + queueDetail.setRequestCount(scenarioCountMap.get(queueDetail.getResourceId())); + } + apiExecutionQueueService.insertQueue(queue, queueDetails); + return queue; + } + + public List getExecutionQueueDetails(List resourceIds, Map caseReportMap) { List queueDetails = new ArrayList<>(); AtomicInteger sort = new AtomicInteger(1); for (String resourceId : resourceIds) { @@ -38,8 +61,7 @@ public class ApiBatchRunBaseService { queueDetail.setReportId(caseReportMap == null ? UUID.randomUUID().toString() : caseReportMap.get(resourceId)); queueDetails.add(queueDetail); } - apiExecutionQueueService.insertQueue(queue, queueDetails); - return queue; + return queueDetails; } private ExecutionQueue getExecutionQueue(ApiRunModeConfigDTO runModeConfig, String resourceType, String userId) { @@ -51,4 +73,5 @@ public class ApiBatchRunBaseService { queue.setUserId(userId); return queue; } + } diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/service/scenario/ApiScenarioBatchRunService.java b/backend/services/api-test/src/main/java/io/metersphere/api/service/scenario/ApiScenarioBatchRunService.java index e9687d3e0c..18682ab932 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/service/scenario/ApiScenarioBatchRunService.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/service/scenario/ApiScenarioBatchRunService.java @@ -1,17 +1,17 @@ package io.metersphere.api.service.scenario; import io.metersphere.api.constants.ApiScenarioStepRefType; +import io.metersphere.api.constants.ApiScenarioStepType; import io.metersphere.api.domain.ApiScenario; import io.metersphere.api.domain.ApiScenarioRecord; import io.metersphere.api.domain.ApiScenarioReport; import io.metersphere.api.domain.ApiScenarioReportStep; +import io.metersphere.api.dto.ApiBatchRunInitReportResult; import io.metersphere.api.dto.ApiScenarioParamConfig; import io.metersphere.api.dto.ApiScenarioParseTmpParam; import io.metersphere.api.dto.debug.ApiResourceRunRequest; import io.metersphere.api.dto.request.MsScenario; -import io.metersphere.api.dto.scenario.ApiScenarioBatchRunRequest; -import io.metersphere.api.dto.scenario.ApiScenarioDetail; -import io.metersphere.api.dto.scenario.ApiScenarioParseParam; +import io.metersphere.api.dto.scenario.*; import io.metersphere.api.service.ApiBatchRunBaseService; import io.metersphere.api.service.ApiExecuteService; import io.metersphere.api.service.queue.ApiExecutionQueueService; @@ -27,6 +27,7 @@ import io.metersphere.sdk.util.DateUtils; import io.metersphere.sdk.util.LogUtils; import io.metersphere.system.uid.IDGenerator; import jakarta.annotation.Resource; +import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -34,7 +35,9 @@ import org.springframework.transaction.annotation.Transactional; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; @Service @Transactional(rollbackFor = Exception.class) @@ -93,13 +96,13 @@ public class ApiScenarioBatchRunService { initIntegratedReport(runModeConfig, ids, userId, request.getProjectId()); } - Map scenarioReportMap = initReport(ids, runModeConfig, userId); + ApiBatchRunInitReportResult reportResult = initReport(ids, runModeConfig, userId); // 集成报告,执行前先设置成 RUNNING setRunningIntegrateReport(runModeConfig); // 先初始化集成报告,设置好报告ID,再初始化执行队列 - ExecutionQueue queue = apiBatchRunBaseService.initExecutionqueue(ids, runModeConfig, ApiExecuteResourceType.API_SCENARIO.name(), scenarioReportMap, userId); + ExecutionQueue queue = apiBatchRunBaseService.initExecutionqueue(ids, runModeConfig, ApiExecuteResourceType.API_SCENARIO.name(), reportResult, userId); // 执行第一个任务 ExecutionQueueDetail nextDetail = apiExecutionQueueService.getNextDetail(queue.getQueueId()); executeNextTask(queue, nextDetail); @@ -122,7 +125,7 @@ public class ApiScenarioBatchRunService { apiExecutionSetService.initSet(apiScenarioReport.getId(), ids); } - Map scenarioReportMap = initReport(ids, runModeConfig, userId); + ApiBatchRunInitReportResult reportResult = initReport(ids, runModeConfig, userId); // 集成报告,执行前先设置成 RUNNING setRunningIntegrateReport(runModeConfig); @@ -141,15 +144,18 @@ public class ApiScenarioBatchRunService { LogUtils.info("当前执行任务的用例已删除 {}", id); break; } - + // 请求数量,集合报告放总的数量,独立报告,放当前场景的请求数量 + Long requestCount; if (runModeConfig.isIntegratedReport()) { // 集成报告生成虚拟的报告ID reportId = IDGenerator.nextStr(); + requestCount = reportResult.getRequestCount(); } else { - reportId = scenarioReportMap.get(id); + reportId = reportResult.getScenarioReportMap().get(id); + requestCount = Optional.ofNullable(reportResult.getScenarioCountMap().get(id)).orElse(0L); } TaskRequestDTO taskRequest = getTaskRequestDTO(reportId, apiScenarioDetail, runModeConfig); - + taskRequest.setRequestCount(requestCount); execute(taskRequest, apiScenarioDetail); } catch (Exception e) { @@ -163,16 +169,26 @@ public class ApiScenarioBatchRunService { } } - private Map initReport(List ids, ApiRunModeConfigDTO runModeConfig, String userId) { + private ApiBatchRunInitReportResult initReport(List ids, ApiRunModeConfigDTO runModeConfig, String userId) { Map scenarioReportMap = new HashMap<>(); + ApiBatchRunInitReportResult reportResult = new ApiBatchRunInitReportResult(); + Map scenarioCountMap = reportResult.getScenarioCountMap(); Boolean isIntegratedReport = runModeConfig.isIntegratedReport(); AtomicInteger sort = new AtomicInteger(1); + // 这里ID顺序和队列的ID顺序保持一致 for (String id : ids) { ApiScenarioDetail apiScenarioDetail = apiScenarioService.get(id); + if (apiScenarioDetail == null) { break; } + + // 记录请求数量 + Long itemCount = getRequestCount(apiScenarioDetail.getSteps()); + scenarioCountMap.put(id, itemCount); + reportResult.setRequestCount(reportResult.getRequestCount() + itemCount); + if (runModeConfig.isIntegratedReport()) { // 初始化集成报告步骤 initIntegratedReportSteps(apiScenarioDetail, runModeConfig.getCollectionReport().getReportId(), sort.getAndIncrement()); @@ -184,7 +200,25 @@ public class ApiScenarioBatchRunService { scenarioReportMap.put(id, reportId); } } - return isIntegratedReport ? null : scenarioReportMap; + + reportResult.setScenarioReportMap(isIntegratedReport ? null : scenarioReportMap); + return reportResult; + } + + + private Long getRequestCount(List steps) { + AtomicLong requestCount = new AtomicLong(); + apiScenarioService.traversalStepTree(steps, step -> { + if (BooleanUtils.isTrue(step.getEnable()) && isRequestStep(step)) { + requestCount.getAndIncrement(); + } + return true; + }); + return requestCount.get(); + } + + private boolean isRequestStep(ApiScenarioStepCommonDTO step) { + return StringUtils.equalsAny(step.getStepType(), ApiScenarioStepType.API.name(), ApiScenarioStepType.API_CASE.name(), ApiScenarioStepType.CUSTOM_REQUEST.name()); } /** @@ -267,6 +301,14 @@ public class ApiScenarioBatchRunService { } TaskRequestDTO taskRequest = getTaskRequestDTO(queueDetail.getReportId(), apiScenarioDetail, queue.getRunModeConfig()); taskRequest.setQueueId(queue.getQueueId()); + // 请求数量,集合报告放总的数量,独立报告,放当前场景的请求数量 + Long requestCount; + if (queue.getRunModeConfig().isIntegratedReport()) { + requestCount = queue.getRequestCount(); + } else { + requestCount = Optional.ofNullable(queueDetail.getRequestCount()).orElse(0L); + } + taskRequest.setRequestCount(requestCount); execute(taskRequest, apiScenarioDetail); } diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/service/scenario/ApiScenarioService.java b/backend/services/api-test/src/main/java/io/metersphere/api/service/scenario/ApiScenarioService.java index 1c0bdf659a..5139efe01b 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/service/scenario/ApiScenarioService.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/service/scenario/ApiScenarioService.java @@ -1019,7 +1019,7 @@ public class ApiScenarioService extends MoveNodeService { /** * 遍历步骤树 */ - private void traversalStepTree(List steps, Function handleStepFunc) { + public void traversalStepTree(List steps, Function handleStepFunc) { if (CollectionUtils.isEmpty(steps)) { return; } @@ -1998,7 +1998,6 @@ public class ApiScenarioService extends MoveNodeService { scenarioSteps.forEach(item -> { // 如果步骤的场景ID不等于当前场景的ID,说明是引用的步骤,如果 parentId 为空,说明是一级子步骤,重新挂载到对应的场景中 if (StringUtils.isEmpty(item.getParentId())) { - item.setParentId(step.getId()); children.add(item); } }); @@ -2010,7 +2009,7 @@ public class ApiScenarioService extends MoveNodeService { // 如果当前步骤是引用的场景,获取该场景的子步骤 Map> childStepMap = scenarioSteps .stream() - .collect(Collectors.groupingBy(ApiScenarioStepDTO::getParentId)); + .collect(Collectors.groupingBy(item -> Optional.ofNullable(item.getParentId()).orElse(StringUtils.EMPTY))); step.setChildren(buildStepTree(children, childStepMap, scenarioStepMap)); } else { if (CollectionUtils.isEmpty(children)) { diff --git a/backend/services/api-test/src/test/java/io/metersphere/api/controller/MsHTTPElementTest.java b/backend/services/api-test/src/test/java/io/metersphere/api/controller/MsHTTPElementTest.java index ec2f39da65..c2ae930771 100644 --- a/backend/services/api-test/src/test/java/io/metersphere/api/controller/MsHTTPElementTest.java +++ b/backend/services/api-test/src/test/java/io/metersphere/api/controller/MsHTTPElementTest.java @@ -431,7 +431,6 @@ public class MsHTTPElementTest { public static MsHTTPElement getMsHttpElement() { MsHTTPElement msHTTPElement = new MsHTTPElement(); - msHTTPElement.setUrl("http://www.test.com"); msHTTPElement.setPath("/test"); msHTTPElement.setMethod("GET"); msHTTPElement.setName("name"); diff --git a/backend/services/project-management/src/main/java/io/metersphere/project/api/KeyValueEnableParam.java b/backend/services/project-management/src/main/java/io/metersphere/project/api/KeyValueEnableParam.java index 7113ac96c8..b98f320132 100644 --- a/backend/services/project-management/src/main/java/io/metersphere/project/api/KeyValueEnableParam.java +++ b/backend/services/project-management/src/main/java/io/metersphere/project/api/KeyValueEnableParam.java @@ -1,6 +1,5 @@ package io.metersphere.project.api; -import jakarta.validation.constraints.Size; import lombok.Data; /** @@ -18,6 +17,5 @@ public class KeyValueEnableParam extends KeyValueParam { /** * 描述 */ - @Size(max = 500) private String description; } diff --git a/backend/services/project-management/src/main/java/io/metersphere/project/api/KeyValueParam.java b/backend/services/project-management/src/main/java/io/metersphere/project/api/KeyValueParam.java index 081af3ba41..dd2ecabec2 100644 --- a/backend/services/project-management/src/main/java/io/metersphere/project/api/KeyValueParam.java +++ b/backend/services/project-management/src/main/java/io/metersphere/project/api/KeyValueParam.java @@ -1,6 +1,5 @@ package io.metersphere.project.api; -import jakarta.validation.constraints.Size; import lombok.Data; import org.apache.commons.lang3.StringUtils; @@ -14,12 +13,10 @@ public class KeyValueParam { /** * 键 */ - @Size(max = 255) private String key; /** * 值 */ - @Size(max = 255) private String value; public boolean isValid() {