refactor(接口测试): http请求详情设置请求方法等信息

This commit is contained in:
AgAngle 2024-03-22 20:52:59 +08:00 committed by Craftsman
parent 6736cc5f17
commit a6000793be
18 changed files with 213 additions and 104 deletions

View File

@ -281,7 +281,7 @@ public class ApiDefinitionController {
@PostMapping("/debug")
@Operation(summary = "接口调试")
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_EXECUTE)
public TaskRequestDTO debug(@Validated @RequestBody ApiRunRequest request) {
public TaskRequestDTO debug(@Validated @RequestBody ApiDefinitionRunRequest request) {
return apiDefinitionService.debug(request);
}

View File

@ -254,7 +254,7 @@ public class ApiTestCaseController {
@PostMapping("/debug")
@Operation(summary = "用例调试")
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_CASE_EXECUTE)
public TaskRequestDTO debug(@Validated @RequestBody ApiRunRequest request) {
public TaskRequestDTO debug(@Validated @RequestBody ApiCaseRunRequest request) {
return apiTestCaseService.debug(request);
}
@ -270,7 +270,7 @@ public class ApiTestCaseController {
@PostMapping("/run")
@Operation(summary = "用例执行,传请求详情执行")
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_CASE_EXECUTE)
public TaskRequestDTO run(@Validated @RequestBody ApiRunRequest request) {
public TaskRequestDTO run(@Validated @RequestBody ApiCaseRunRequest request) {
return apiTestCaseService.run(request, SessionUtils.getUserId());
}

View File

@ -3,15 +3,24 @@ package io.metersphere.api.dto;
import lombok.Data;
/**
* 执行时需要设置的接口信息
* @Author: jianxing
* @CreateTime: 2024-02-17 18:46
*/
@Data
public class ApiResourceModuleInfo {
public class ApiDefinitionExecuteInfo {
/**
* 模块Id
*/
private String moduleId;
/**
* 请求方法
*/
private String method;
/**
* 请求路径
*/
private String path;
/**
* 资源id接口定义接口用例等
*/

View File

@ -0,0 +1,16 @@
package io.metersphere.api.dto.definition;
import io.metersphere.api.dto.debug.ApiDebugRunRequest;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
@Data
public class ApiCaseRunRequest extends ApiDebugRunRequest {
@Schema(description = "环境ID")
private String environmentId;
@Schema(description = "接口定义ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank
private String apiDefinitionId;
}

View File

@ -0,0 +1,24 @@
package io.metersphere.api.dto.definition;
import io.metersphere.api.dto.debug.ApiDebugRunRequest;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
@Data
public class ApiDefinitionRunRequest extends ApiDebugRunRequest {
@Schema(description = "环境ID")
private String environmentId;
@Schema(description = "http协议类型post/get/其它协议则是协议名(mqtt)")
@NotBlank
private String method;
@Schema(description = "http协议路径/其它协议则为空")
@NotBlank
private String path;
@Schema(description = "模块fk")
private String moduleId;
}

View File

@ -2,7 +2,7 @@ package io.metersphere.api.mapper;
import io.metersphere.api.domain.ApiDefinition;
import io.metersphere.api.domain.ApiDefinitionCustomField;
import io.metersphere.api.dto.ApiResourceModuleInfo;
import io.metersphere.api.dto.ApiDefinitionExecuteInfo;
import io.metersphere.api.dto.ReferenceDTO;
import io.metersphere.api.dto.ReferenceRequest;
import io.metersphere.api.dto.converter.ApiDefinitionImportDetail;
@ -67,7 +67,7 @@ public interface ExtApiDefinitionMapper {
Long getLastPos(@Param("projectId") String projectId, @Param("basePos") Long basePos);
List<ApiResourceModuleInfo> getModuleInfoByIds(@Param("ids") List<String> ids);
List<ApiDefinitionExecuteInfo> getApiDefinitionExecuteInfo(@Param("ids") List<String> ids);
ApiDefinition selectByProjectNumAndApiNum(@Param("projectNum") String projectNum, @Param("apiNum") String apiNum);

View File

@ -547,10 +547,11 @@
</if>
order by `pos` desc limit 1;
</select>
<select id="getModuleInfoByIds" resultType="io.metersphere.api.dto.ApiResourceModuleInfo">
select id as resource_id, module_id
<select id="getApiDefinitionExecuteInfo" resultType="io.metersphere.api.dto.ApiDefinitionExecuteInfo">
select id as resource_id, module_id, path, method
from api_definition
where id in
where protocol = 'HTTP'
and id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>

View File

@ -1,5 +1,7 @@
package io.metersphere.api.service;
import io.metersphere.api.domain.ApiDefinition;
import io.metersphere.api.dto.ApiDefinitionExecuteInfo;
import io.metersphere.api.dto.ApiFile;
import io.metersphere.api.dto.definition.ResponseBinaryBody;
import io.metersphere.api.dto.definition.ResponseBody;
@ -21,6 +23,7 @@ import io.metersphere.project.dto.CommonScriptInfo;
import io.metersphere.project.service.CustomFunctionService;
import io.metersphere.project.service.FileAssociationService;
import io.metersphere.project.service.FileMetadataService;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.JSON;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
@ -266,4 +269,58 @@ public class ApiCommonService {
}
return null;
}
/**
* 设置 MsHTTPElement 中的 method 等信息
* @param httpElements
* @param getDefinitionInfoFunc
*/
public void setApiDefinitionExecuteInfo(List<MsHTTPElement> httpElements, Function<List<String>, List<ApiDefinitionExecuteInfo>> getDefinitionInfoFunc) {
if (CollectionUtils.isNotEmpty(httpElements)) {
List<String> resourceIds = httpElements.stream().map(MsHTTPElement::getResourceId).collect(Collectors.toList());
// 获取接口模块信息
Map<String, ApiDefinitionExecuteInfo> resourceModuleMap = getApiDefinitionExecuteInfoMap(getDefinitionInfoFunc, resourceIds);
httpElements.forEach(httpElement -> {
ApiDefinitionExecuteInfo definitionExecuteInfo = resourceModuleMap.get(httpElement.getResourceId());
// httpElement 设置模块,请求方法等信息
setApiDefinitionExecuteInfo(httpElement, definitionExecuteInfo);
});
}
}
/**
* 获取资源 ID 和接口定义信息 Map
* @param getDefinitionInfoFunc
* @param resourceIds
* @return
*/
public Map<String, ApiDefinitionExecuteInfo> getApiDefinitionExecuteInfoMap(Function<List<String>, List<ApiDefinitionExecuteInfo>> getDefinitionInfoFunc, List<String> resourceIds) {
Map<String, ApiDefinitionExecuteInfo> resourceModuleMap = getDefinitionInfoFunc.apply(resourceIds)
.stream()
.collect(Collectors.toMap(ApiDefinitionExecuteInfo::getResourceId, Function.identity()));
return resourceModuleMap;
}
/**
* 设置 MsHTTPElement 中的 method 等信息
* @param msTestElement
* @param definitionExecuteInfo
*/
public void setApiDefinitionExecuteInfo(AbstractMsTestElement msTestElement, ApiDefinitionExecuteInfo definitionExecuteInfo) {
if (msTestElement instanceof MsHTTPElement httpElement && definitionExecuteInfo != null) {
httpElement.setModuleId(definitionExecuteInfo.getModuleId());
httpElement.setMethod(definitionExecuteInfo.getMethod());
httpElement.setPath(definitionExecuteInfo.getPath());
}
}
/**
* httpElement 设置接口定义参数
* @param apiDefinition
* @param msTestElement
*/
public void setApiDefinitionExecuteInfo(AbstractMsTestElement msTestElement, ApiDefinition apiDefinition) {
setApiDefinitionExecuteInfo(msTestElement, BeanUtils.copyBean(new ApiDefinitionExecuteInfo(), apiDefinition));
}
}

View File

@ -257,10 +257,6 @@ public class ApiDefinitionService extends MoveNodeService {
checkResponseNameCode(request.getResponse());
if (originApiDefinition.getProtocol().equals(ModuleConstants.NODE_PROTOCOL_HTTP)) {
checkUpdateExist(apiDefinition, originApiDefinition);
//http协议的接口如果修改了path和method需要同步把case的path和method修改
if (!originApiDefinition.getPath().equals(apiDefinition.getPath()) || !originApiDefinition.getMethod().equals(apiDefinition.getMethod())) {
apiTestCaseService.updateByApiDefinitionId(List.of(request.getId()), apiDefinition);
}
}
apiDefinition.setUpdateUser(userId);
apiDefinition.setUpdateTime(System.currentTimeMillis());
@ -880,6 +876,7 @@ public class ApiDefinitionService extends MoveNodeService {
public ApiDefinitionDTO getApiDefinitionInfo(String id, String userId, ApiDefinition apiDefinition) {
ApiDefinitionDTO apiDefinitionDTO = new ApiDefinitionDTO();
BeanUtils.copyBean(apiDefinitionDTO, apiDefinition);
// 2. 使用Optional避免空指针异常
handleBlob(id, apiDefinitionDTO);
// 3. 查询自定义字段
@ -888,7 +885,6 @@ public class ApiDefinitionService extends MoveNodeService {
ApiDefinitionFollowerExample example = new ApiDefinitionFollowerExample();
example.createCriteria().andApiDefinitionIdEqualTo(id).andUserIdEqualTo(userId);
apiDefinitionDTO.setFollow(apiDefinitionFollowerMapper.countByExample(example) > 0);
BeanUtils.copyBean(apiDefinitionDTO, apiDefinition);
Set<String> userIds = extractUserIds(List.of(apiDefinitionDTO));
Map<String, String> userMap = userLoginService.getUserNameMap(new ArrayList<>(userIds));
apiDefinitionDTO.setCreateUserName(userMap.get(apiDefinitionDTO.getCreateUser()));
@ -900,8 +896,11 @@ public class ApiDefinitionService extends MoveNodeService {
Optional<ApiDefinitionBlob> apiDefinitionBlobOptional = Optional.ofNullable(apiDefinitionBlobMapper.selectByPrimaryKey(id));
apiDefinitionBlobOptional.ifPresent(blob -> {
AbstractMsTestElement msTestElement = ApiDataUtils.parseObject(new String(blob.getRequest()), AbstractMsTestElement.class);
apiCommonService.setLinkFileInfo(id, msTestElement);
apiCommonService.setEnableCommonScriptProcessorInfo(msTestElement);
apiCommonService.setApiDefinitionExecuteInfo(msTestElement, apiDefinitionDTO);
apiDefinitionDTO.setRequest(msTestElement);
// blob.getResponse() null 时不进行转换
if (blob.getResponse() != null) {
@ -1117,8 +1116,8 @@ public class ApiDefinitionService extends MoveNodeService {
}
}
public List<ApiResourceModuleInfo> getModuleInfoByIds(List<String> apiIds) {
return extApiDefinitionMapper.getModuleInfoByIds(apiIds);
public List<ApiDefinitionExecuteInfo> getModuleInfoByIds(List<String> apiIds) {
return extApiDefinitionMapper.getApiDefinitionExecuteInfo(apiIds);
}
public void checkModuleExist(String moduleId) {
@ -1171,7 +1170,7 @@ public class ApiDefinitionService extends MoveNodeService {
return apiFileResourceService.transfer(request, userId, ApiResourceType.API.name());
}
public TaskRequestDTO debug(ApiRunRequest request) {
public TaskRequestDTO debug(ApiDefinitionRunRequest request) {
ApiResourceRunRequest runRequest = apiExecuteService.getApiResourceRunRequest(request);
EnvironmentInfoDTO environmentInfoDTO = environmentService.get(request.getEnvironmentId());
ApiParamConfig apiParamConfig = apiExecuteService.getApiParamConfig(request.getReportId());
@ -1182,8 +1181,13 @@ public class ApiDefinitionService extends MoveNodeService {
taskRequest.setResourceType(ApiResourceType.API.name());
taskRequest.setRunMode(apiExecuteService.getDebugRunModule(request.getFrontendDebug()));
AbstractMsTestElement msTestElement = runRequest.getTestElement();
// 设置 method 等信息
apiCommonService.setApiDefinitionExecuteInfo(msTestElement, BeanUtils.copyBean(new ApiDefinition(), request));
// 设置环境
apiParamConfig.setEnvConfig(environmentInfoDTO);
return apiExecuteService.apiExecute(runRequest, taskRequest, apiParamConfig);
}

View File

@ -1,13 +1,16 @@
package io.metersphere.api.service.definition;
import io.metersphere.api.domain.*;
import io.metersphere.api.dto.ApiDefinitionExecuteInfo;
import io.metersphere.api.dto.ApiParamConfig;
import io.metersphere.api.dto.debug.ApiResourceRunRequest;
import io.metersphere.api.dto.definition.ApiTestCaseBatchRunRequest;
import io.metersphere.api.mapper.ApiDefinitionMapper;
import io.metersphere.api.mapper.ApiTestCaseBlobMapper;
import io.metersphere.api.mapper.ApiTestCaseMapper;
import io.metersphere.api.mapper.ExtApiTestCaseMapper;
import io.metersphere.api.service.ApiBatchRunBaseService;
import io.metersphere.api.service.ApiCommonService;
import io.metersphere.api.service.ApiExecuteService;
import io.metersphere.api.service.queue.ApiExecutionQueueService;
import io.metersphere.api.service.queue.ApiExecutionSetService;
@ -63,6 +66,10 @@ public class ApiTestCaseBatchRunService {
private ApiReportService apiReportService;
@Resource
private ApiBatchRunBaseService apiBatchRunBaseService;
@Resource
private ApiCommonService apiCommonService;
@Resource
private ApiDefinitionMapper apiDefinitionMapper;
/**
* 异步批量执行
@ -132,6 +139,8 @@ public class ApiTestCaseBatchRunService {
// 分批处理
SubListUtils.dealForSubList(ids, 100, subIds -> {
List<ApiTestCase> apiTestCases = extApiTestCaseMapper.getApiCaseExecuteInfoByIds(subIds);
// 获取用例和定义信息的mapkey 为用例IDvalue 为接口定义信息
Map<String, ApiDefinitionExecuteInfo> definitionExecuteInfoMap = apiCommonService.getApiDefinitionExecuteInfoMap(apiTestCaseService::getModuleInfoByIds, subIds);
Map<String, String> caseReportMap = null;
String integratedReportId = null;
@ -174,7 +183,7 @@ public class ApiTestCaseBatchRunService {
// 如果是集成报告则生成唯一的虚拟ID非集成报告使用单用例的报告ID
reportId = runModeConfig.isIntegratedReport() ? UUID.randomUUID().toString() : caseReportMap.get(id);
TaskRequestDTO taskRequest = getTaskRequestDTO(reportId, apiTestCase, runModeConfig);
execute(taskRequest, apiTestCase, apiTestCaseBlob);
execute(taskRequest, apiTestCase, apiTestCaseBlob, definitionExecuteInfoMap.get(apiTestCase.getId()));
} catch (Exception e) {
LogUtils.error("执行用例失败 {}-{}", reportId, id);
LogUtils.error(e);
@ -270,6 +279,7 @@ public class ApiTestCaseBatchRunService {
LogUtils.info("当前执行任务的用例已删除 {}", resourceId);
return;
}
ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey(apiTestCase.getApiDefinitionId());
String reportId;
if (runModeConfig.isIntegratedReport()) {
@ -281,7 +291,7 @@ public class ApiTestCaseBatchRunService {
}
TaskRequestDTO taskRequest = getTaskRequestDTO(reportId, apiTestCase, runModeConfig);
taskRequest.setQueueId(queue.getQueueId());
execute(taskRequest, apiTestCase, apiTestCaseBlob);
execute(taskRequest, apiTestCase, apiTestCaseBlob, BeanUtils.copyBean(new ApiDefinitionExecuteInfo(), apiDefinition));
}
/**
@ -290,12 +300,16 @@ public class ApiTestCaseBatchRunService {
* @param apiTestCase
* @param apiTestCaseBlob
*/
public void execute(TaskRequestDTO taskRequest, ApiTestCase apiTestCase, ApiTestCaseBlob apiTestCaseBlob) {
public void execute(TaskRequestDTO taskRequest, ApiTestCase apiTestCase, ApiTestCaseBlob apiTestCaseBlob, ApiDefinitionExecuteInfo definitionExecuteInfo) {
ApiParamConfig apiParamConfig = apiExecuteService.getApiParamConfig(taskRequest.getReportId());
apiParamConfig.setEnvConfig(environmentService.get(getEnvId(taskRequest.getRunModeConfig(), apiTestCase)));
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);
}

View File

@ -7,7 +7,6 @@ import io.metersphere.api.dto.debug.ApiFileResourceUpdateRequest;
import io.metersphere.api.dto.debug.ApiResourceRunRequest;
import io.metersphere.api.dto.definition.*;
import io.metersphere.api.dto.request.ApiTransferRequest;
import io.metersphere.api.dto.request.http.MsHTTPElement;
import io.metersphere.api.mapper.*;
import io.metersphere.api.service.ApiCommonService;
import io.metersphere.api.service.ApiExecuteService;
@ -224,6 +223,7 @@ public class ApiTestCaseService extends MoveNodeService {
AbstractMsTestElement msTestElement = ApiDataUtils.parseObject(new String(testCaseBlob.getRequest()), AbstractMsTestElement.class);
apiCommonService.setLinkFileInfo(id, msTestElement);
apiCommonService.setEnableCommonScriptProcessorInfo(msTestElement);
apiCommonService.setApiDefinitionExecuteInfo(msTestElement, apiDefinition);
apiTestCaseDTO.setRequest(msTestElement);
return apiTestCaseDTO;
}
@ -518,37 +518,6 @@ public class ApiTestCaseService extends MoveNodeService {
return apiFileResourceService.uploadTempFile(file);
}
public void updateByApiDefinitionId(List<String> ids, ApiDefinition apiDefinition) {
String method = apiDefinition.getMethod();
String path = apiDefinition.getPath();
if (StringUtils.isNotEmpty(method) || StringUtils.isNotEmpty(path)) {
ApiTestCaseExample apiTestCaseExample = new ApiTestCaseExample();
apiTestCaseExample.createCriteria().andApiDefinitionIdIn(ids);
List<ApiTestCase> caseLists = apiTestCaseMapper.selectByExample(apiTestCaseExample);
List<String> caseIds = caseLists.stream().map(ApiTestCase::getId).toList();
if (CollectionUtils.isEmpty(caseIds)) {
return;
}
ApiTestCaseBlobExample blobExample = new ApiTestCaseBlobExample();
blobExample.createCriteria().andIdIn(caseIds);
List<ApiTestCaseBlob> bloBs = apiTestCaseBlobMapper.selectByExampleWithBLOBs(blobExample);
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ApiTestCaseBlobMapper batchMapper = sqlSession.getMapper(ApiTestCaseBlobMapper.class);
bloBs.forEach(apiTestCase -> {
MsHTTPElement msHttpElement = ApiDataUtils.parseObject(new String(apiTestCase.getRequest()), MsHTTPElement.class);
msHttpElement.setMethod(method);
msHttpElement.setPath(path);
apiTestCase.setRequest(ApiDataUtils.toJSONString(msHttpElement).getBytes());
batchMapper.updateByPrimaryKeySelective(apiTestCase);
});
sqlSession.flushStatements();
if (sqlSessionFactory != null) {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
}
}
public List<ApiTestCaseBlob> getBlobByIds(List<String> apiCaseIds) {
if (CollectionUtils.isEmpty(apiCaseIds)) {
return Collections.emptyList();
@ -590,7 +559,7 @@ public class ApiTestCaseService extends MoveNodeService {
apiTestCaseMapper.updateByPrimaryKeySelective(update);
}
public List<ApiResourceModuleInfo> getModuleInfoByIds(List<String> ids) {
public List<ApiDefinitionExecuteInfo> getModuleInfoByIds(List<String> ids) {
// 获取接口定义ID和用例ID的映射
Map<String, String> apiCaseDefinitionMap = extApiTestCaseMapper.getApiCaseDefinitionInfo(ids)
.stream()
@ -600,11 +569,11 @@ public class ApiTestCaseService extends MoveNodeService {
if (CollectionUtils.isEmpty(definitionIds)) {
return List.of();
}
List<ApiResourceModuleInfo> moduleInfos = extApiDefinitionMapper.getModuleInfoByIds(definitionIds);
List<ApiDefinitionExecuteInfo> definitionExecuteInfos = extApiDefinitionMapper.getApiDefinitionExecuteInfo(definitionIds);
// resourceId 从定义ID替换成用例ID
moduleInfos.forEach(moduleInfo ->
moduleInfo.setResourceId(apiCaseDefinitionMap.get(moduleInfo.getResourceId())));
return moduleInfos;
definitionExecuteInfos.forEach(info ->
info.setResourceId(apiCaseDefinitionMap.get(info.getResourceId())));
return definitionExecuteInfos;
}
public void handleFileAssociationUpgrade(FileAssociation originFileAssociation, FileMetadata newFileMetadata) {
@ -636,7 +605,7 @@ public class ApiTestCaseService extends MoveNodeService {
* @param request
* @return
*/
public TaskRequestDTO run(ApiRunRequest request, String userId) {
public TaskRequestDTO run(ApiCaseRunRequest request, String userId) {
ApiTestCase apiTestCase = checkResourceExist(request.getId());
ApiResourceRunRequest runRequest = apiExecuteService.getApiResourceRunRequest(request);
apiTestCase.setEnvironmentId(request.getEnvironmentId());
@ -689,7 +658,7 @@ public class ApiTestCaseService extends MoveNodeService {
// 初始化报告
initApiReport(apiTestCase, reportId, poolId, userId);
return doExecute(taskRequest, runRequest, apiTestCase.getEnvironmentId());
return doExecute(taskRequest, runRequest, apiTestCase.getApiDefinitionId(), apiTestCase.getEnvironmentId());
}
/**
@ -698,7 +667,7 @@ public class ApiTestCaseService extends MoveNodeService {
* @param request
* @return
*/
public TaskRequestDTO debug(ApiRunRequest request) {
public TaskRequestDTO debug(ApiCaseRunRequest request) {
TaskRequestDTO taskRequest = getTaskRequest(request.getReportId(), request.getId(),
request.getProjectId(), apiExecuteService.getDebugRunModule(request.getFrontendDebug()));
taskRequest.setSaveResult(false);
@ -706,14 +675,19 @@ public class ApiTestCaseService extends MoveNodeService {
ApiResourceRunRequest runRequest = apiExecuteService.getApiResourceRunRequest(request);
return doExecute(taskRequest, runRequest, request.getEnvironmentId());
return doExecute(taskRequest, runRequest, request.getApiDefinitionId(), request.getEnvironmentId());
}
private TaskRequestDTO doExecute(TaskRequestDTO taskRequest, ApiResourceRunRequest runRequest, String envId) {
private TaskRequestDTO doExecute(TaskRequestDTO taskRequest, ApiResourceRunRequest runRequest, String apiDefinitionId, String envId) {
ApiParamConfig apiParamConfig = apiExecuteService.getApiParamConfig(taskRequest.getReportId());
ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey(apiDefinitionId);
// 设置环境
apiParamConfig.setEnvConfig(environmentService.get(envId));
// 设置 method 等信息
apiCommonService.setApiDefinitionExecuteInfo(runRequest.getTestElement(), apiDefinition);
return apiExecuteService.apiExecute(runRequest, taskRequest, apiParamConfig);
}

View File

@ -29,17 +29,13 @@ import io.metersphere.sdk.util.BeanUtils;
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;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
@Service
@Transactional(rollbackFor = Exception.class)

View File

@ -1110,6 +1110,7 @@ public class ApiScenarioService extends MoveNodeService {
ApiScenarioParseParam parseParam,
String reportId, String userId) {
// 解析生成场景树并保存临时变量
ApiScenarioParseTmpParam tmpParam = parse(msScenario, steps, parseParam);
ApiResourceRunRequest runRequest = getApiResourceRunRequest(msScenario, tmpParam);
@ -1283,7 +1284,7 @@ public class ApiScenarioService extends MoveNodeService {
parseStep2MsElement(msScenario, steps, tmpParam);
// 设置 HttpElement 的模块信息
setHttpElementModuleId(tmpParam.getStepTypeHttpElementMap());
setApiDefinitionExecuteInfo(tmpParam.getStepTypeHttpElementMap());
// 设置使用脚本前后置的公共脚本信息
apiCommonService.setEnableCommonScriptProcessorInfo(tmpParam.getCommonElements());
@ -1304,23 +1305,9 @@ public class ApiScenarioService extends MoveNodeService {
*
* @param stepTypeHttpElementMap
*/
private void setHttpElementModuleId(Map<String, List<MsHTTPElement>> stepTypeHttpElementMap) {
setHttpElementModuleId(stepTypeHttpElementMap.get(ApiScenarioStepType.API.name()), apiDefinitionService::getModuleInfoByIds);
setHttpElementModuleId(stepTypeHttpElementMap.get(ApiScenarioStepType.API_CASE.name()), apiTestCaseService::getModuleInfoByIds);
}
private void setHttpElementModuleId(List<MsHTTPElement> httpElements, Function<List<String>, List<ApiResourceModuleInfo>> getModuleInfoFunc) {
if (CollectionUtils.isNotEmpty(httpElements)) {
List<String> apiIds = httpElements.stream().map(MsHTTPElement::getResourceId).collect(Collectors.toList());
// 获取接口模块信息
Map<String, String> resourceModuleMap = getModuleInfoFunc.apply(apiIds)
.stream()
.collect(Collectors.toMap(ApiResourceModuleInfo::getResourceId, ApiResourceModuleInfo::getModuleId));
httpElements.forEach(httpElement -> {
// httpElement 设置模块信息
httpElement.setModuleId(resourceModuleMap.get(httpElement.getResourceId()));
});
}
private void setApiDefinitionExecuteInfo(Map<String, List<MsHTTPElement>> stepTypeHttpElementMap) {
apiCommonService.setApiDefinitionExecuteInfo(stepTypeHttpElementMap.get(ApiScenarioStepType.API.name()), apiDefinitionService::getModuleInfoByIds);
apiCommonService.setApiDefinitionExecuteInfo(stepTypeHttpElementMap.get(ApiScenarioStepType.API_CASE.name()), apiTestCaseService::getModuleInfoByIds);
}
/**
@ -1615,7 +1602,7 @@ public class ApiScenarioService extends MoveNodeService {
*/
private boolean hasStepDetail(String stepType) {
return !StringUtils.equals(stepType, ApiScenarioStepRefType.REF.name())
|| StringUtils.equals(stepType, ApiScenarioStepType.API.name());
|| isApi(stepType);
}
private Map<String, String> getResourceDetailMap(Map<String, List<String>> refResourceMap) {
@ -1772,7 +1759,15 @@ public class ApiScenarioService extends MoveNodeService {
* 引用的接口定义允许修改参数值需要特殊处理
*/
private boolean isRefApi(String stepType, String refType) {
return StringUtils.equals(stepType, ApiScenarioStepType.API.name()) && StringUtils.equals(refType, ApiScenarioStepRefType.REF.name());
return isApi(stepType) && StringUtils.equals(refType, ApiScenarioStepRefType.REF.name());
}
private boolean isApi(String stepType) {
return StringUtils.equals(stepType, ApiScenarioStepType.API.name());
}
private boolean isApiCase(String stepType) {
return StringUtils.equals(stepType, ApiScenarioStepType.API_CASE.name());
}
/**
@ -1865,6 +1860,14 @@ public class ApiScenarioService extends MoveNodeService {
// 设置关联的文件的最新信息
if (isRef(step.getRefType())) {
apiCommonService.setLinkFileInfo(step.getResourceId(), msTestElement);
if (isApi(step.getStepType())) {
ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey(step.getResourceId());
apiCommonService.setApiDefinitionExecuteInfo(msTestElement, apiDefinition);
} else if (isApiCase(step.getStepType())) {
ApiTestCase apiTestCase = apiTestCaseMapper.selectByPrimaryKey(step.getResourceId());
ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey(apiTestCase.getApiDefinitionId());
apiCommonService.setApiDefinitionExecuteInfo(msTestElement, apiDefinition);
}
} else {
apiCommonService.setLinkFileInfo(step.getScenarioId(), msTestElement);
}

View File

@ -414,6 +414,10 @@ public class ApiDefinitionControllerTests extends BaseTest {
if (apiDefinitionBlob != null) {
AbstractMsTestElement msTestElement = ApiDataUtils.parseObject(new String(apiDefinitionBlob.getRequest()), AbstractMsTestElement.class);
apiCommonService.setLinkFileInfo(apiDefinition.getId(), msTestElement);
MsHTTPElement msHTTPElement = (MsHTTPElement) msTestElement;
msHTTPElement.setMethod(apiDefinition.getMethod());
msHTTPElement.setPath(apiDefinition.getPath());
msHTTPElement.setModuleId(apiDefinition.getModuleId());
copyApiDefinitionDTO.setRequest(msTestElement);
List<HttpResponse> httpResponses = ApiDataUtils.parseArray(new String(apiDefinitionBlob.getResponse()), HttpResponse.class);
for (HttpResponse httpResponse : httpResponses) {
@ -421,6 +425,11 @@ public class ApiDefinitionControllerTests extends BaseTest {
}
copyApiDefinitionDTO.setResponse(httpResponses);
}
MsHTTPElement msHTTPElement = (MsHTTPElement) apiDefinitionDTO.getRequest();
Assertions.assertEquals(msHTTPElement.getMethod(), apiDefinition.getMethod());
Assertions.assertEquals(msHTTPElement.getPath(), apiDefinition.getPath());
Assertions.assertEquals(msHTTPElement.getModuleId(), apiDefinition.getModuleId());
Assertions.assertEquals(apiDefinitionDTO, copyApiDefinitionDTO);
assertErrorCode(this.requestGet(GET + "111"), ApiResultCode.API_DEFINITION_NOT_EXIST);
@ -568,19 +577,7 @@ public class ApiDefinitionControllerTests extends BaseTest {
}
updateRequest.setPath("/api/test/path/method/case");
this.requestPostWithOk(UPDATE, updateRequest);
//校验用例是否被修改
ApiTestCaseExample apiTestCaseExample = new ApiTestCaseExample();
apiTestCaseExample.createCriteria().andApiDefinitionIdEqualTo(apiPathAndMethod.getId());
List<ApiTestCase> apiTestCases = apiTestCaseMapper.selectByExample(apiTestCaseExample);
List<String> caseIds = apiTestCases.stream().map(ApiTestCase::getId).toList();
ApiTestCaseBlobExample apiTestCaseBlobExample = new ApiTestCaseBlobExample();
apiTestCaseBlobExample.createCriteria().andIdIn(caseIds);
List<ApiTestCaseBlob> apiTestCaseBlobs = apiTestCaseBlobMapper.selectByExampleWithBLOBs(apiTestCaseBlobExample);
apiTestCaseBlobs.forEach(apiTestCaseBlob -> {
MsHTTPElement caseElement = ApiDataUtils.parseObject(new String(apiTestCaseBlob.getRequest()), MsHTTPElement.class);
Assertions.assertEquals(updateRequest.getPath(), caseElement.getPath());
Assertions.assertEquals(updateRequest.getMethod(), caseElement.getMethod());
});
// @@校验权限
request.setId(apiDefinition.getId());
request.setName("permission-st-6");
@ -591,7 +588,7 @@ public class ApiDefinitionControllerTests extends BaseTest {
@Test
@Order(4)
public void debug() throws Exception {
ApiRunRequest request = new ApiRunRequest();
ApiDefinitionRunRequest request = new ApiDefinitionRunRequest();
request.setId(apiDefinition.getId());
MsHTTPElement msHTTPElement = new MsHTTPElement();
msHTTPElement.setPath("/test");
@ -599,6 +596,8 @@ public class ApiDefinitionControllerTests extends BaseTest {
request.setRequest(JSON.parseObject(ApiDataUtils.toJSONString(msHTTPElement)));
request.setReportId(IDGenerator.nextStr());
request.setProjectId(DEFAULT_PROJECT_ID);
request.setPath("/test");
request.setMethod("GET");
MvcResult mvcResult = this.requestPostAndReturn(DEBUG, request);
ResultHolder resultHolder = JSON.parseObject(mvcResult.getResponse().getContentAsString(Charset.defaultCharset()), ResultHolder.class);
Assertions.assertTrue(resultHolder.getCode() == ApiResultCode.RESOURCE_POOL_EXECUTE_ERROR.getCode() ||

View File

@ -420,7 +420,7 @@ public class ApiTestCaseControllerTests extends BaseTest {
@Test
@Order(3)
public void debug() throws Exception {
ApiRunRequest request = new ApiRunRequest();
ApiCaseRunRequest request = new ApiCaseRunRequest();
request.setId(apiTestCase.getId());
MsHTTPElement msHTTPElement = new MsHTTPElement();
msHTTPElement.setPath("/test");
@ -428,6 +428,7 @@ public class ApiTestCaseControllerTests extends BaseTest {
request.setRequest(JSON.parseObject(ApiDataUtils.toJSONString(msHTTPElement)));
request.setReportId(IDGenerator.nextStr());
request.setProjectId(DEFAULT_PROJECT_ID);
request.setApiDefinitionId(apiTestCase.getApiDefinitionId());
MvcResult mvcResult = this.requestPostAndReturn(DEBUG, request);
ResultHolder resultHolder = JSON.parseObject(mvcResult.getResponse().getContentAsString(Charset.defaultCharset()), ResultHolder.class);
Assertions.assertTrue(resultHolder.getCode() == ApiResultCode.RESOURCE_POOL_EXECUTE_ERROR.getCode() ||
@ -548,8 +549,18 @@ public class ApiTestCaseControllerTests extends BaseTest {
copyApiDebugDTO.setFollow(CollectionUtils.isNotEmpty(followers));
AbstractMsTestElement msTestElement = ApiDataUtils.parseObject(new String(apiTestCaseBlob.getRequest()), AbstractMsTestElement.class);
apiCommonService.setLinkFileInfo(apiTestCase.getId(), msTestElement);
MsHTTPElement msHTTPElement = (MsHTTPElement) msTestElement;
msHTTPElement.setMethod(apiDefinition.getMethod());
msHTTPElement.setPath(apiDefinition.getPath());
msHTTPElement.setModuleId(apiDefinition.getModuleId());
copyApiDebugDTO.setRequest(msTestElement);
msHTTPElement = (MsHTTPElement) apiDebugDTO.getRequest();
Assertions.assertEquals(msHTTPElement.getMethod(), apiDefinition.getMethod());
Assertions.assertEquals(msHTTPElement.getPath(), apiDefinition.getPath());
Assertions.assertEquals(msHTTPElement.getModuleId(), apiDefinition.getModuleId());
Assertions.assertEquals(apiDebugDTO, copyApiDebugDTO);
this.requestGetWithOk(GET + anotherApiTestCase.getId())
.andReturn();

View File

@ -380,6 +380,7 @@ export interface ExecuteRequestParams {
request: ExecuteApiRequestFullParams | ExecutePluginRequestParams;
projectId: string;
frontendDebug?: boolean; // 是否本地调试,该模式下接口会返回执行参数,用来调用本地执行服务
apiDefinitionId?: string | number; // 接口用例执行和调试时需要传
}
// 响应结果
export interface ResponseResult {

View File

@ -345,7 +345,6 @@ export interface AddApiCaseParams extends ExecuteRequestParams {
name: string;
priority: string;
status: string;
apiDefinitionId?: string | number;
tags: string[];
deleteFileIds?: string[];
unLinkFileIds?: string[];

View File

@ -108,6 +108,7 @@
environmentId: props.environmentId as string,
frontendDebug: executeType === 'localExec',
reportId: reportId.value,
apiDefinitionId: caseDetail.value.apiDefinitionId,
};
debugSocket(executeType); // websocket
if (!(caseDetail.value.id as string).startsWith('c') && executeType === 'serverExec') {