fix(接口测试): 执行时场景步骤文件找不到

This commit is contained in:
AgAngle 2024-05-13 11:24:41 +08:00 committed by Craftsman
parent bcd06b5e27
commit 5e8034ae51
23 changed files with 198 additions and 135 deletions

View File

@ -0,0 +1,9 @@
package io.metersphere.sdk.constants;
/**
* @Author: jianxing
* @CreateTime: 2023-11-16 16:57
*/
public enum ApiFileResourceType {
API_DEBUG, API, API_CASE, API_SCENARIO, API_SCENARIO_STEP, API_MOCK
}

View File

@ -30,8 +30,17 @@ public class ApiExecuteFileInfo implements Serializable {
* 资源ID
*/
private String resourceId;
/**
* 场景ID
* resourceType API_SCENARIO_STEP
* 该字段保存场景ID
*/
private String scenarioId;
/**
* 资源类型
* {@link io.metersphere.sdk.constants.ApiFileResourceType}
*/
private String resourceType;

View File

@ -9,6 +9,7 @@ import io.metersphere.api.service.ApiFileResourceService;
import io.metersphere.api.service.debug.ApiDebugLogService;
import io.metersphere.api.service.debug.ApiDebugService;
import io.metersphere.project.service.FileModuleService;
import io.metersphere.sdk.constants.DefaultRepositoryDir;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
import io.metersphere.system.dto.sdk.BaseTreeNode;
@ -109,7 +110,8 @@ public class ApiDebugController {
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
@RequiresPermissions(PermissionConstants.PROJECT_FILE_MANAGEMENT_READ_ADD)
public String transfer(@Validated @RequestBody ApiTransferRequest request) {
return apiFileResourceService.transfer(request, SessionUtils.getUserId(), ApiResourceType.API_DEBUG.name());
String apiDebugDir = DefaultRepositoryDir.getApiDebugDir(request.getProjectId(), request.getSourceId());
return apiFileResourceService.transfer(request, SessionUtils.getUserId(), apiDebugDir);
}
@GetMapping("/transfer/options/{projectId}")

View File

@ -18,6 +18,7 @@ import io.metersphere.api.service.definition.ApiDefinitionNoticeService;
import io.metersphere.api.service.definition.ApiDefinitionService;
import io.metersphere.api.utils.JsonSchemaBuilder;
import io.metersphere.project.service.FileModuleService;
import io.metersphere.sdk.constants.DefaultRepositoryDir;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
import io.metersphere.system.dto.OperationHistoryDTO;
@ -275,7 +276,8 @@ public class ApiDefinitionController {
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
@RequiresPermissions(PermissionConstants.PROJECT_FILE_MANAGEMENT_READ_ADD)
public String transfer(@Validated @RequestBody ApiTransferRequest request) {
return apiFileResourceService.transfer(request, SessionUtils.getUserId(), ApiResourceType.API.name());
String apiDefinitionDir = DefaultRepositoryDir.getApiDefinitionDir(request.getProjectId(), request.getSourceId());
return apiFileResourceService.transfer(request, SessionUtils.getUserId(), apiDefinitionDir);
}
@PostMapping("/preview")

View File

@ -20,6 +20,7 @@ import io.metersphere.api.service.definition.ApiDefinitionMockLogService;
import io.metersphere.api.service.definition.ApiDefinitionMockNoticeService;
import io.metersphere.api.service.definition.ApiDefinitionMockService;
import io.metersphere.project.service.FileModuleService;
import io.metersphere.sdk.constants.DefaultRepositoryDir;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.system.dto.OperationHistoryDTO;
import io.metersphere.system.dto.request.OperationHistoryRequest;
@ -156,7 +157,8 @@ public class ApiDefinitionMockController {
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
@RequiresPermissions(PermissionConstants.PROJECT_FILE_MANAGEMENT_READ_ADD)
public String transfer(@Validated @RequestBody ApiTransferRequest request) {
return apiFileResourceService.transfer(request, SessionUtils.getUserId(), ApiResourceType.API_MOCK.name());
String apiMockDir = DefaultRepositoryDir.getApiMockDir(request.getProjectId(), request.getSourceId());
return apiFileResourceService.transfer(request, SessionUtils.getUserId(), apiMockDir);
}
@GetMapping("/get-url/{id}")

View File

@ -2,7 +2,6 @@ package io.metersphere.api.controller.definition;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.api.constants.ApiResourceType;
import io.metersphere.api.domain.ApiTestCase;
import io.metersphere.api.dto.ReferenceDTO;
import io.metersphere.api.dto.ReferenceRequest;
@ -11,6 +10,7 @@ import io.metersphere.api.dto.request.ApiTransferRequest;
import io.metersphere.api.service.ApiFileResourceService;
import io.metersphere.api.service.definition.*;
import io.metersphere.project.service.FileModuleService;
import io.metersphere.sdk.constants.DefaultRepositoryDir;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
import io.metersphere.system.dto.OperationHistoryDTO;
@ -245,7 +245,8 @@ public class ApiTestCaseController {
@RequiresPermissions(PermissionConstants.PROJECT_FILE_MANAGEMENT_READ_ADD)
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
public String transfer(@Validated @RequestBody ApiTransferRequest request) {
return apiFileResourceService.transfer(request, SessionUtils.getUserId(), ApiResourceType.API_CASE.name());
String apiCaseDir = DefaultRepositoryDir.getApiCaseDir(request.getProjectId(), request.getSourceId());
return apiFileResourceService.transfer(request, SessionUtils.getUserId(), apiCaseDir);
}
@GetMapping("/transfer/options/{projectId}")

View File

@ -3,7 +3,6 @@ package io.metersphere.api.controller.scenario;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.api.constants.ApiResource;
import io.metersphere.api.constants.ApiResourceType;
import io.metersphere.api.domain.ApiScenario;
import io.metersphere.api.dto.ReferenceDTO;
import io.metersphere.api.dto.ReferenceRequest;
@ -275,7 +274,15 @@ public class ApiScenarioController {
@RequiresPermissions(PermissionConstants.PROJECT_FILE_MANAGEMENT_READ_ADD)
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
public String transfer(@Validated @RequestBody ApiTransferRequest request) {
return apiFileResourceService.transfer(request, SessionUtils.getUserId(), ApiResourceType.API_SCENARIO.name());
return apiScenarioService.scenarioTransfer(request, SessionUtils.getUserId());
}
@PostMapping("/step/transfer")
@Operation(summary = "接口测试-接口场景管理-场景步骤-附件-文件转存")
@RequiresPermissions(PermissionConstants.PROJECT_FILE_MANAGEMENT_READ_ADD)
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
public String stepTransfer(@Validated @RequestBody ApiTransferRequest request) {
return apiScenarioService.stepTransfer(request, SessionUtils.getUserId());
}
@GetMapping("/transfer/options/{projectId}")

View File

@ -50,10 +50,14 @@ public class ApiScenarioParseTmpParam {
*/
private List<MsScriptElement> scriptElements = new ArrayList<>();
/**
* 执行的资源ID列表
* 场景执行时为关联的所有用例和场景列表
* 执行时包含文件的资源 ID 列表
* 场景执行时包含 用例场景步骤ID
*/
private Set<String> refResourceIds = HashSet.newHashSet(0);
private Set<String> fileResourceIds = HashSet.newHashSet(0);
/**
* 包含文件文件的步骤ID和场景ID的映射
*/
private Map<String, String> fileStepScenarioMap = new HashMap<>(0);
/**
* 执行的资源所属项目的ID列表
* 场景执行时为引用的资源的项目ID列表

View File

@ -1,6 +1,6 @@
package io.metersphere.api.dto.debug;
import io.metersphere.api.constants.ApiResourceType;
import io.metersphere.sdk.constants.ApiFileResourceType;
import lombok.Data;
import java.io.Serial;
@ -24,7 +24,7 @@ public class ApiFileResourceUpdateRequest implements Serializable {
/**
* 资源类型
*/
private ApiResourceType apiResourceType;
private ApiFileResourceType apiResourceType;
/**
* 关联的资源ID
*/

View File

@ -4,10 +4,7 @@ import io.metersphere.plugin.api.spi.AbstractMsTestElement;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
@Data
public class ApiResourceRunRequest {
@ -27,10 +24,14 @@ public class ApiResourceRunRequest {
@Schema(description = "关联文件ID")
private List<String> linkFileIds = new ArrayList<>(0);
/**
* 执行的资源ID列表
* 场景执行时为关联的所有用例和场景列表
* 执行时包含文件的资源 ID 列表
* 场景执行时包含 用例场景步骤ID
*/
private Set<String> refResourceIds = HashSet.newHashSet(0);
private Set<String> fileResourceIds = HashSet.newHashSet(0);
/**
* 包含文件文件的步骤ID和场景ID的映射
*/
private Map<String, String> fileStepScenarioMap = new HashMap<>(0);
/**
* 执行的资源所属项目的ID列表
* 场景执行时为引用的资源的项目ID列表

View File

@ -50,6 +50,7 @@ public class ApiScenarioScheduleJob extends BaseScheduleJob {
apiRunModeConfigDTO.setPoolId(apiExecuteService.getProjectApiResourcePoolId(apiScenarioDetail.getProjectId()));
}
msScenario.setResourceId(apiScenarioDetail.getId());
// 解析生成场景树并保存临时变量
ApiScenarioParseTmpParam tmpParam = apiScenarioService.parse(msScenario, apiScenarioDetail.getSteps(), parseParam);

View File

@ -19,10 +19,7 @@ import io.metersphere.project.dto.customfunction.request.CustomFunctionRunReques
import io.metersphere.project.dto.environment.GlobalParams;
import io.metersphere.project.dto.environment.GlobalParamsDTO;
import io.metersphere.project.service.*;
import io.metersphere.sdk.constants.ApiExecuteResourceType;
import io.metersphere.sdk.constants.ApiExecuteRunMode;
import io.metersphere.sdk.constants.ProjectApplicationType;
import io.metersphere.sdk.constants.StorageType;
import io.metersphere.sdk.constants.*;
import io.metersphere.sdk.dto.api.task.ApiExecuteFileInfo;
import io.metersphere.sdk.dto.api.task.ApiRunModeConfigDTO;
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
@ -370,38 +367,42 @@ public class ApiExecuteService {
* @param taskRequest
*/
private void setTaskRefFileParam(ApiResourceRunRequest runRequest, TaskRequestDTO taskRequest) {
// 查询包括引用的资源所需的文件
Set<String> resourceIdsSet = runRequest.getRefResourceIds();
// 查询包括资源所需的文件
Set<String> resourceIdsSet = runRequest.getFileResourceIds();
resourceIdsSet.add(taskRequest.getResourceId());
List<String> resourceIds = resourceIdsSet.stream().collect(Collectors.toList());
SubListUtils.dealForSubList(resourceIds, 50, subResourceIds -> {
// 查询通过本地上传的文件
List<ApiExecuteFileInfo> localFiles = apiFileResourceService.getByResourceIds(subResourceIds).
stream()
.map(file -> {
ApiExecuteFileInfo apiExecuteFileInfo = getApiExecuteFileInfo(file.getFileId(), file.getFileName(), file.getProjectId());
// 本地上传的文件需要 resourceId 查询对应的目录
apiExecuteFileInfo.setResourceId(file.getResourceId());
apiExecuteFileInfo.setResourceType(file.getResourceType());
if (StringUtils.equals(file.getResourceType(), ApiFileResourceType.API_SCENARIO_STEP.name())) {
apiExecuteFileInfo.setScenarioId(runRequest.getFileStepScenarioMap().get(file.getResourceId()));
}
return apiExecuteFileInfo;
})
.collect(Collectors.toList());
taskRequest.setLocalFiles(localFiles);
// 查询通过本地上传的文件
List<ApiExecuteFileInfo> localFiles = apiFileResourceService.getByResourceIds(resourceIds).
stream()
.map(file -> {
ApiExecuteFileInfo apiExecuteFileInfo = getApiExecuteFileInfo(file.getFileId(), file.getFileName(), file.getProjectId());
// 本地上传的文件需要 resourceId 查询对应的目录
apiExecuteFileInfo.setResourceId(file.getResourceId());
apiExecuteFileInfo.setResourceType(file.getResourceType());
return apiExecuteFileInfo;
})
.collect(Collectors.toList());
taskRequest.setLocalFiles(localFiles);
// 查询关联的文件管理的文件
List<ApiExecuteFileInfo> refFiles = fileAssociationService.getFiles(resourceIds).
stream()
.map(file -> {
ApiExecuteFileInfo refFileInfo = getApiExecuteFileInfo(file.getFileId(), file.getOriginalName(),
file.getProjectId(), file.getStorage());
if (StorageType.isGit(file.getStorage())) {
// 设置Git信息
refFileInfo.setFileMetadataRepositoryDTO(fileManagementService.getFileMetadataRepositoryDTO(file.getMetadataId()));
refFileInfo.setFileModuleRepositoryDTO(fileManagementService.getFileModuleRepositoryDTO(file.getModuleId()));
}
return refFileInfo;
}).collect(Collectors.toList());
taskRequest.setRefFiles(refFiles);
// 查询关联的文件管理的文件
List<ApiExecuteFileInfo> refFiles = fileAssociationService.getFiles(subResourceIds).
stream()
.map(file -> {
ApiExecuteFileInfo refFileInfo = getApiExecuteFileInfo(file.getFileId(), file.getOriginalName(),
file.getProjectId(), file.getStorage());
if (StorageType.isGit(file.getStorage())) {
// 设置Git信息
refFileInfo.setFileMetadataRepositoryDTO(fileManagementService.getFileMetadataRepositoryDTO(file.getMetadataId()));
refFileInfo.setFileModuleRepositoryDTO(fileManagementService.getFileModuleRepositoryDTO(file.getModuleId()));
}
return refFileInfo;
}).collect(Collectors.toList());
taskRequest.setRefFiles(refFiles);
});
}
private List<ApiExecuteFileInfo> getApiExecuteFileInfo(List<FileMetadata> fileMetadataList) {

View File

@ -1,6 +1,6 @@
package io.metersphere.api.service;
import io.metersphere.api.constants.ApiResourceType;
import io.metersphere.sdk.constants.ApiFileResourceType;
import io.metersphere.api.domain.ApiFileResource;
import io.metersphere.api.domain.ApiFileResourceExample;
import io.metersphere.api.dto.debug.ApiFileResourceUpdateRequest;
@ -115,7 +115,7 @@ public class ApiFileResourceService {
List<String> uploadFileIds = resourceUpdateRequest.getUploadFileIds();
String resourceId = resourceUpdateRequest.getResourceId();
String projectId = resourceUpdateRequest.getProjectId();
ApiResourceType apiResourceType = resourceUpdateRequest.getApiResourceType();
ApiFileResourceType apiResourceType = resourceUpdateRequest.getApiResourceType();
// 处理本地上传文件
if (CollectionUtils.isNotEmpty(uploadFileIds)) {
@ -374,58 +374,44 @@ public class ApiFileResourceService {
* * api正式文件存储路径DefaultRepositoryDir.getApiDir(projectId, resourceId) + "/" + fileId+fileName
* * apiTestCase文件存储路径DefaultRepositoryDir.getApiCaseDir()+fileId+fileName
* * apiScenario文件存储路径DefaultRepositoryDir.getApiScenarioDir()+fileId+fileName
* * apiScenario文件存储路径DefaultRepositoryDir.getApiScenarioDir()+fileId+fileName
*/
public String transfer(ApiTransferRequest request, String currentUser, String type) {
public String transfer(ApiTransferRequest request, String currentUser, String folder) {
ApiFileResourceExample example = new ApiFileResourceExample();
example.createCriteria().andFileIdEqualTo(request.getFileId()).andResourceIdEqualTo(request.getSourceId()).andResourceTypeEqualTo(type);
example.createCriteria()
.andFileIdEqualTo(request.getFileId())
.andResourceIdEqualTo(request.getSourceId());
List<ApiFileResource> apiFileResources = apiFileResourceMapper.selectByExample(example);
String fileName;
String fileId;
boolean isTemp = false;
ApiResourceType apiResourceType = ApiResourceType.valueOf(type);
String apiFolder = switch (apiResourceType) {
case API_DEBUG ->
DefaultRepositoryDir.getApiDebugDir(request.getProjectId(), request.getSourceId()) + "/" + request.getFileId();
case API ->
DefaultRepositoryDir.getApiDefinitionDir(request.getProjectId(), request.getSourceId()) + "/" + request.getFileId();
case API_CASE ->
DefaultRepositoryDir.getApiCaseDir(request.getProjectId(), request.getSourceId()) + "/" + request.getFileId();
case API_SCENARIO ->
DefaultRepositoryDir.getApiScenarioDir(request.getProjectId(), request.getSourceId()) + "/" + request.getFileId();
case API_MOCK ->
DefaultRepositoryDir.getApiMockDir(request.getProjectId(), request.getSourceId()) + "/" + request.getFileId();
default -> throw new MSException("file type error!");
};
if (CollectionUtils.isEmpty(apiFileResources)) {
//需要判断文件是否是在临时文件夹中
// 需要判断文件是否是在临时文件夹中
fileName = getTempFileNameByFileId(request.getFileId());
apiFolder = StringUtils.join(DefaultRepositoryDir.getSystemTempDir(), "/", request.getFileId());
folder = DefaultRepositoryDir.getSystemTempDir();
if (StringUtils.isEmpty(fileName)) {
throw new MSException("file not found!");
}
isTemp = true;
} else {
fileName = apiFileResources.get(0).getFileName();
}
folder += "/" + request.getFileId();
FileRequest fileRequest = new FileRequest();
fileRequest.setFolder(apiFolder);
fileRequest.setFolder(folder);
fileRequest.setFileName(fileName);
fileRequest.setStorage(StorageType.MINIO.name());
byte[] bytes;
try {
bytes = fileService.download(fileRequest);
if (isTemp) {
//删除临时文件
fileId = fileMetadataService.transferFile(request.getFileName(), request.getOriginalName(), request.getProjectId(), request.getModuleId(), currentUser, fileService.download(fileRequest));
if (CollectionUtils.isEmpty(apiFileResources)) {
// 删除临时文件
FileRequest deleteRequest = new FileRequest();
deleteRequest.setFolder(DefaultRepositoryDir.getSystemTempDir() + "/" + request.getFileId());
deleteRequest.setFolder(folder);
FileCenter.getDefaultRepository().deleteFolder(deleteRequest);
}
} catch (Exception e) {
throw new MSException("download file error!");
}
try {
fileId = fileMetadataService.transferFile(request.getFileName(), request.getOriginalName(), request.getProjectId(), request.getModuleId(), currentUser, bytes);
} catch (Exception e) {
LogUtils.error(e);
throw new MSException(Translator.get("file.transfer.failed"));
}
return fileId;

View File

@ -1,5 +1,6 @@
package io.metersphere.api.service.debug;
import io.metersphere.sdk.constants.ApiFileResourceType;
import io.metersphere.api.constants.ApiResourceType;
import io.metersphere.api.domain.ApiDebug;
import io.metersphere.api.domain.ApiDebugBlob;
@ -128,7 +129,7 @@ public class ApiDebugService extends MoveNodeService {
resourceUpdateRequest.setProjectId(projectId);
resourceUpdateRequest.setFolder(apiDebugDir);
resourceUpdateRequest.setResourceId(sourceId);
resourceUpdateRequest.setApiResourceType(ApiResourceType.API_DEBUG);
resourceUpdateRequest.setApiResourceType(ApiFileResourceType.API_DEBUG);
resourceUpdateRequest.setOperator(operator);
resourceUpdateRequest.setLogModule(OperationLogModule.API_TEST_DEBUG_MANAGEMENT_DEBUG);
resourceUpdateRequest.setFileAssociationSourceType(FileAssociationSourceUtil.SOURCE_TYPE_API_DEBUG);

View File

@ -1,6 +1,6 @@
package io.metersphere.api.service.definition;
import io.metersphere.api.constants.ApiResourceType;
import io.metersphere.sdk.constants.ApiFileResourceType;
import io.metersphere.api.controller.result.ApiResultCode;
import io.metersphere.api.domain.*;
import io.metersphere.api.dto.ApiFile;
@ -218,7 +218,7 @@ public class ApiDefinitionMockService {
resourceUpdateRequest.setProjectId(projectId);
resourceUpdateRequest.setFolder(apiDefinitionMockDir);
resourceUpdateRequest.setResourceId(sourceId);
resourceUpdateRequest.setApiResourceType(ApiResourceType.API_MOCK);
resourceUpdateRequest.setApiResourceType(ApiFileResourceType.API_MOCK);
resourceUpdateRequest.setOperator(operator);
resourceUpdateRequest.setLogModule(OperationLogModule.API_TEST_MANAGEMENT_MOCK);
resourceUpdateRequest.setFileAssociationSourceType(FileAssociationSourceUtil.SOURCE_TYPE_API_DEFINITION_MOCK);

View File

@ -2,6 +2,7 @@ package io.metersphere.api.service.definition;
import io.metersphere.api.constants.ApiConstants;
import io.metersphere.api.constants.ApiDefinitionDocType;
import io.metersphere.sdk.constants.ApiFileResourceType;
import io.metersphere.api.constants.ApiResourceType;
import io.metersphere.api.controller.result.ApiResultCode;
import io.metersphere.api.domain.*;
@ -241,7 +242,7 @@ public class ApiDefinitionService extends MoveNodeService {
resourceUpdateRequest.setProjectId(projectId);
resourceUpdateRequest.setFolder(apiDefinitionDir);
resourceUpdateRequest.setResourceId(sourceId);
resourceUpdateRequest.setApiResourceType(ApiResourceType.API);
resourceUpdateRequest.setApiResourceType(ApiFileResourceType.API);
resourceUpdateRequest.setOperator(operator);
resourceUpdateRequest.setLogModule(OperationLogModule.API_TEST_MANAGEMENT_DEFINITION);
resourceUpdateRequest.setFileAssociationSourceType(FileAssociationSourceUtil.SOURCE_TYPE_API_DEFINITION);

View File

@ -1,5 +1,6 @@
package io.metersphere.api.service.definition;
import io.metersphere.sdk.constants.ApiFileResourceType;
import io.metersphere.api.constants.ApiResourceType;
import io.metersphere.api.domain.*;
import io.metersphere.api.dto.*;
@ -147,7 +148,7 @@ public class ApiTestCaseService extends MoveNodeService {
resourceUpdateRequest.setProjectId(projectId);
resourceUpdateRequest.setFolder(apiDebugDir);
resourceUpdateRequest.setResourceId(sourceId);
resourceUpdateRequest.setApiResourceType(ApiResourceType.API_CASE);
resourceUpdateRequest.setApiResourceType(ApiFileResourceType.API_CASE);
resourceUpdateRequest.setOperator(operator);
resourceUpdateRequest.setLogModule(OperationLogModule.API_TEST_MANAGEMENT_CASE);
resourceUpdateRequest.setFileAssociationSourceType(FileAssociationSourceUtil.SOURCE_TYPE_API_TEST_CASE);

View File

@ -333,6 +333,7 @@ public class ApiScenarioBatchRunService {
// 记录请求数量
taskRequest.setRequestCount(getRequestCount(apiScenarioDetail.getSteps()));
msScenario.setResourceId(apiScenarioDetail.getId());
ApiScenarioParseTmpParam tmpParam = apiScenarioService.parse(msScenario, apiScenarioDetail.getSteps(), parseParam);
ApiResourceRunRequest runRequest = apiScenarioService.getApiResourceRunRequest(msScenario, tmpParam);

View File

@ -1,5 +1,6 @@
package io.metersphere.api.service.scenario;
import io.metersphere.sdk.constants.ApiFileResourceType;
import io.metersphere.api.constants.ApiResourceType;
import io.metersphere.api.constants.ApiScenarioStepRefType;
import io.metersphere.api.constants.ApiScenarioStepType;
@ -95,7 +96,6 @@ import org.quartz.CronTrigger;
import org.quartz.TriggerBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.text.SimpleDateFormat;
import java.util.*;
@ -493,15 +493,33 @@ public class ApiScenarioService extends MoveNodeService {
if (MapUtils.isNotEmpty(stepFileParam)) {
stepFileParam.forEach((stepId, fileParam) -> {
// 处理步骤文件
ApiFileResourceUpdateRequest resourceUpdateRequest = getApiFileResourceUpdateRequest(stepId, scenario.getProjectId(), creator);
resourceUpdateRequest.setFileAssociationSourceType(FileAssociationSourceUtil.SOURCE_TYPE_API_SCENARIO_STEP);
resourceUpdateRequest.setUploadFileIds(fileParam.getUploadFileIds());
resourceUpdateRequest.setLinkFileIds(fileParam.getLinkFileIds());
ApiFileResourceUpdateRequest resourceUpdateRequest = getStepApiFileResourceUpdateRequest(creator, scenario, stepId, fileParam);
apiFileResourceService.addFileResource(resourceUpdateRequest);
});
}
}
private void handleStepFiles(ApiScenarioUpdateRequest request, String updater, ApiScenario scenario) {
Map<String, ResourceUpdateFileParam> stepFileParam = request.getStepFileParam();
if (MapUtils.isNotEmpty(stepFileParam)) {
stepFileParam.forEach((stepId, fileParam) -> {
// 处理步骤文件
ApiFileResourceUpdateRequest resourceUpdateRequest = getStepApiFileResourceUpdateRequest(updater, scenario, stepId, fileParam);
apiFileResourceService.updateFileResource(resourceUpdateRequest);
});
}
}
private ApiFileResourceUpdateRequest getStepApiFileResourceUpdateRequest(String userId, ApiScenario scenario, String stepId, ResourceAddFileParam fileParam) {
ApiFileResourceUpdateRequest resourceUpdateRequest = getApiFileResourceUpdateRequest(stepId, scenario.getProjectId(), userId);
String apiScenarioStepDir = DefaultRepositoryDir.getApiScenarioStepDir(scenario.getProjectId(), scenario.getId(), stepId);
resourceUpdateRequest.setFileAssociationSourceType(FileAssociationSourceUtil.SOURCE_TYPE_API_SCENARIO_STEP);
resourceUpdateRequest.setApiResourceType(ApiFileResourceType.API_SCENARIO_STEP);
resourceUpdateRequest.setFolder(apiScenarioStepDir);
resourceUpdateRequest = BeanUtils.copyBean(resourceUpdateRequest, fileParam);
return resourceUpdateRequest;
}
private void saveStepCsv(List<ApiScenarioStep> steps, List<ApiScenarioCsvStep> csvSteps) {
//获取所有的步骤id 然后删掉历史的关联关系
List<String> stepIds = steps.stream().map(ApiScenarioStep::getId).toList();
@ -727,19 +745,6 @@ public class ApiScenarioService extends MoveNodeService {
}
}
private void handleStepFiles(ApiScenarioUpdateRequest request, String updater, ApiScenario scenario) {
Map<String, ResourceUpdateFileParam> stepFileParam = request.getStepFileParam();
if (MapUtils.isNotEmpty(stepFileParam)) {
stepFileParam.forEach((stepId, fileParam) -> {
// 处理步骤文件
ApiFileResourceUpdateRequest resourceUpdateRequest = getApiFileResourceUpdateRequest(stepId, scenario.getProjectId(), updater);
resourceUpdateRequest.setFileAssociationSourceType(FileAssociationSourceUtil.SOURCE_TYPE_API_SCENARIO_STEP);
resourceUpdateRequest = BeanUtils.copyBean(resourceUpdateRequest, fileParam);
apiFileResourceService.updateFileResource(resourceUpdateRequest);
});
}
}
/**
* 更新场景步骤
*/
@ -1113,7 +1118,7 @@ public class ApiScenarioService extends MoveNodeService {
resourceUpdateRequest.setProjectId(projectId);
resourceUpdateRequest.setFolder(apiScenarioDir);
resourceUpdateRequest.setResourceId(sourceId);
resourceUpdateRequest.setApiResourceType(ApiResourceType.API_SCENARIO);
resourceUpdateRequest.setApiResourceType(ApiFileResourceType.API_SCENARIO);
resourceUpdateRequest.setOperator(operator);
resourceUpdateRequest.setLogModule(OperationLogModule.API_SCENARIO_MANAGEMENT_SCENARIO);
resourceUpdateRequest.setFileAssociationSourceType(FileAssociationSourceUtil.SOURCE_TYPE_API_SCENARIO);
@ -1284,6 +1289,7 @@ public class ApiScenarioService extends MoveNodeService {
private ApiScenario checkResourceExist(String id) {
return ServiceUtils.checkResourceExist(apiScenarioMapper.selectByPrimaryKey(id), "permission.system_api_scenario.name");
}
public TaskRequestDTO debug(ApiScenarioDebugRequest request) {
ApiScenario apiScenario = apiScenarioMapper.selectByPrimaryKey(request.getId());
boolean hasSave = apiScenario != null;
@ -1293,6 +1299,7 @@ public class ApiScenarioService extends MoveNodeService {
msScenario.setRefType(ApiScenarioStepRefType.DIRECT.name());
msScenario.setScenarioConfig(getScenarioConfig(request, hasSave));
msScenario.setProjectId(request.getProjectId());
msScenario.setResourceId(request.getId());
// 处理特殊的步骤详情
addSpecialStepDetails(request.getSteps(), request.getStepDetails());
@ -1402,6 +1409,8 @@ public class ApiScenarioService extends MoveNodeService {
String reportId,
String userId) {
msScenario.setResourceId(apiScenario.getId());
// 解析生成场景树并保存临时变量
ApiScenarioParseTmpParam tmpParam = parse(msScenario, steps, parseParam);
@ -1559,7 +1568,8 @@ public class ApiScenarioService extends MoveNodeService {
}
private ApiResourceRunRequest setApiResourceRunRequestParam(MsScenario msScenario, ApiScenarioParseTmpParam tmpParam, ApiResourceRunRequest runRequest) {
runRequest.setRefResourceIds(tmpParam.getRefResourceIds());
runRequest.setFileResourceIds(tmpParam.getFileResourceIds());
runRequest.setFileStepScenarioMap(tmpParam.getFileStepScenarioMap());
runRequest.setRefProjectIds(tmpParam.getRefProjectIds());
runRequest.setTestElement(msScenario);
return runRequest;
@ -1591,7 +1601,7 @@ public class ApiScenarioService extends MoveNodeService {
// 获取场景环境相关配置
tmpParam.setScenarioParseEnvInfo(getScenarioParseEnvInfo(refResourceMap, parseParam.getEnvironmentId(), parseParam.getGrouped()));
parseStep2MsElement(msScenario, steps, tmpParam);
parseStep2MsElement(msScenario, steps, tmpParam, msScenario.getResourceId());
// 设置 HttpElement 的模块信息
setApiDefinitionExecuteInfo(tmpParam.getUniqueIdStepMap(), tmpParam.getStepTypeHttpElementMap());
@ -1756,7 +1766,8 @@ public class ApiScenarioService extends MoveNodeService {
*/
private void parseStep2MsElement(AbstractMsTestElement parentElement,
List<? extends ApiScenarioStepCommonDTO> steps,
ApiScenarioParseTmpParam parseParam) {
ApiScenarioParseTmpParam parseParam,
String scenarioId) {
if (CollectionUtils.isNotEmpty(steps)) {
parentElement.setChildren(new LinkedList<>());
}
@ -1802,7 +1813,14 @@ public class ApiScenarioService extends MoveNodeService {
// 记录引用的资源ID和项目ID下载执行文件时需要使用
parseParam.getRefProjectIds().add(step.getProjectId());
parseParam.getRefResourceIds().add(step.getResourceId());
if (isRefOrPartialRef(step.getRefType())) {
// 引用的步骤记录引用的资源ID
parseParam.getFileResourceIds().add(step.getResourceId());
} else if (msTestElement instanceof MsHTTPElement) {
// 非引用的步骤记录步骤ID
parseParam.getFileResourceIds().add(step.getId());
parseParam.getFileStepScenarioMap().put(step.getId(), scenarioId);
}
// 设置环境等运行时场景参数
setMsScenarioParam(parseParam.getScenarioParseEnvInfo(), step, msTestElement);
@ -1814,7 +1832,10 @@ public class ApiScenarioService extends MoveNodeService {
parentElement.getChildren().add(msTestElement);
if (CollectionUtils.isNotEmpty(step.getChildren())) {
parseStep2MsElement(msTestElement, step.getChildren(), parseParam);
if (isScenarioStep(step.getStepType()) && isRefOrPartialRef(step.getRefType())) {
scenarioId = step.getResourceId();
}
parseStep2MsElement(msTestElement, step.getChildren(), parseParam, scenarioId);
}
}
}
@ -2888,8 +2909,19 @@ public class ApiScenarioService extends MoveNodeService {
}
}
public String transfer(ApiTransferRequest request, String userId) {
return apiFileResourceService.transfer(request, userId, ApiResourceType.API_SCENARIO.name());
public String scenarioTransfer(ApiTransferRequest request, String userId) {
String apiScenarioStepDir = DefaultRepositoryDir.getApiScenarioDir(request.getProjectId(), request.getSourceId());
return apiFileResourceService.transfer(request, userId, apiScenarioStepDir);
}
public String stepTransfer(ApiTransferRequest request, String userId) {
ApiScenarioStep apiScenarioStep = apiScenarioStepMapper.selectByPrimaryKey(request.getSourceId());
if (apiScenarioStep == null) {
return apiFileResourceService.transfer(request, userId, StringUtils.EMPTY);
} else {
String apiScenarioStepDir = DefaultRepositoryDir.getApiScenarioStepDir(request.getProjectId(), apiScenarioStep.getScenarioId(), request.getSourceId());
return apiFileResourceService.transfer(request, userId, apiScenarioStepDir);
}
}
public List<ReferenceDTO> getReference(ReferenceRequest request) {
@ -2922,10 +2954,10 @@ public class ApiScenarioService extends MoveNodeService {
resourceInfo.setProjectId(apiTestCase.getProjectId());
});
}
Optional.ofNullable(apiStepResourceInfo).ifPresent(resourceInfo -> {
Project project = projectMapper.selectByPrimaryKey(resourceInfo.getProjectId());
resourceInfo.setProjectName(project.getName());
});
Optional.ofNullable(apiStepResourceInfo).ifPresent(resourceInfo -> {
Project project = projectMapper.selectByPrimaryKey(resourceInfo.getProjectId());
resourceInfo.setProjectName(project.getName());
});
return apiStepResourceInfo;
}

View File

@ -33,6 +33,7 @@ import {
ScenarioPageUrl,
ScenarioScheduleConfigDeleteUrl,
ScenarioScheduleConfigUrl,
ScenarioStepTransferFileUrl,
ScenarioTransferFileUrl,
ScenarioTransferModuleOptionsUrl,
ScenarioTrashPageUrl,
@ -251,6 +252,10 @@ export function transferFile(data: TransferFileParams) {
return MSR.post({ url: ScenarioTransferFileUrl, data });
}
export function stepTransferFile(data: TransferFileParams) {
return MSR.post({ url: ScenarioStepTransferFileUrl, data });
}
// 文件转存目录
export function getTransferOptions(projectId: string) {
return MSR.get<ModuleTreeNode[]>({ url: ScenarioTransferModuleOptionsUrl, params: projectId });

View File

@ -12,6 +12,7 @@ export const UpdateScenarioUrl = '/api/scenario/update'; // 更新接口场景
export const RecycleScenarioUrl = '/api/scenario/delete-to-gc'; // 删除接口场景
export const ScenarioUploadTempFileUrl = '/api/scenario/upload/temp/file'; // 接口场景上传临时文件
export const ScenarioTransferFileUrl = '/api/scenario/transfer'; // 接口场景临时文件转存
export const ScenarioStepTransferFileUrl = '/api/scenario/step/transfer'; // 接口场景步骤临时文件转存
export const ScenarioTransferModuleOptionsUrl = '/api/scenario/transfer/options'; // 接口场景临时文件转存目录
export const DebugScenarioUrl = '/api/scenario/debug'; // 接口场景调试(不保存报告)
export const ExecuteScenarioUrl = '/api/scenario/run'; // 接口场景执行(保存报告)

View File

@ -237,8 +237,8 @@
:disabled-param-value="!isEditableApi && !isEditableParamValue"
:disabled-except-param="!isEditableApi"
:upload-temp-file-api="uploadTempFile"
:file-save-as-source-id="scenarioId"
:file-save-as-api="transferFile"
:file-save-as-source-id="props.step?.id"
:file-save-as-api="stepTransferFile"
:file-module-options-api="getTransferOptions"
@change="handleActiveDebugChange"
/>
@ -351,7 +351,7 @@
import { getPluginScript, getProtocolList } from '@/api/modules/api-test/common';
import { getDefinitionDetail } from '@/api/modules/api-test/management';
import { getTransferOptions, transferFile, uploadTempFile } from '@/api/modules/api-test/scenario';
import { getTransferOptions, stepTransferFile, uploadTempFile } from '@/api/modules/api-test/scenario';
import { useI18n } from '@/hooks/useI18n';
import { useAppStore } from '@/store';
import { getGenerateId, parseQueryParams } from '@/utils';

View File

@ -156,10 +156,10 @@
v-model:params="requestVModel.body"
:disabled-param-value="!isEditableApi"
:disabled-except-param="!isEditableApi"
:upload-temp-file-api="uploadTempFileCase"
:file-save-as-source-id="scenarioId"
:file-save-as-api="transferFileCase"
:file-module-options-api="getTransferOptionsCase"
:upload-temp-file-api="uploadTempFile"
:file-save-as-source-id="activeStep?.id"
:file-save-as-api="stepTransferFile"
:file-module-options-api="getTransferOptions"
@change="handleActiveDebugChange"
/>
<httpQuery
@ -266,12 +266,8 @@
import { RequestParam } from '@/views/api-test/scenario/components/common/customApiDrawer.vue';
import { getPluginScript, getProtocolList } from '@/api/modules/api-test/common';
import {
getCaseDetail,
getTransferOptionsCase,
transferFileCase,
uploadTempFileCase,
} from '@/api/modules/api-test/management';
import { getCaseDetail } from '@/api/modules/api-test/management';
import { getTransferOptions, stepTransferFile, uploadTempFile } from '@/api/modules/api-test/scenario';
import { useAppStore } from '@/store';
import { characterLimit } from '@/utils';
import { scrollIntoView } from '@/utils/dom';
@ -989,7 +985,7 @@
stepName: activeStep.value?.name || res.name,
name: res.name, // requestnamenull
resourceId: res.id,
stepId: activeStep.value?.uniqueId || '',
stepId: props.request?.stepId || '',
...parseRequestBodyResult,
};
nextTick(() => {
@ -1034,7 +1030,7 @@
...defaultApiParams,
...props.request,
isNew: false,
stepId: activeStep.value?.uniqueId || '',
stepId: props.request?.stepId || '',
stepName: activeStep.value?.name || props.request?.name || '',
});
if (isQuote.value || isCopyNeedInit.value) {