feat(接口测试): 添加执行文件下载接口
This commit is contained in:
parent
bc85e9e40d
commit
49942eb646
|
@ -1,14 +1,13 @@
|
|||
package io.metersphere.api.controller;
|
||||
|
||||
import io.metersphere.api.service.ApiExecuteService;
|
||||
import io.metersphere.sdk.file.FileRequest;
|
||||
import io.metersphere.sdk.util.LogUtils;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
|
@ -27,6 +26,7 @@ public class ApiExecuteResourceController {
|
|||
|
||||
/**
|
||||
* 获取执行脚本
|
||||
*
|
||||
* @param reportId
|
||||
* @param testId
|
||||
* @return
|
||||
|
@ -39,4 +39,18 @@ public class ApiExecuteResourceController {
|
|||
stringRedisTemplate.delete(key);
|
||||
return Optional.ofNullable(script).orElse(StringUtils.EMPTY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载执行所需的文件
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/file")
|
||||
public void downloadFile(@RequestParam("reportId") String reportId,
|
||||
@RequestParam("testId") String testId,
|
||||
@RequestBody FileRequest fileRequest,
|
||||
HttpServletResponse response) throws Exception {
|
||||
apiExecuteService.downloadFile(reportId, testId, fileRequest, response);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,6 +24,9 @@ import io.metersphere.sdk.dto.api.task.ApiExecuteFileInfo;
|
|||
import io.metersphere.sdk.dto.api.task.ApiRunModeConfigDTO;
|
||||
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
|
||||
import io.metersphere.sdk.exception.MSException;
|
||||
import io.metersphere.sdk.file.FileCenter;
|
||||
import io.metersphere.sdk.file.FileRepository;
|
||||
import io.metersphere.sdk.file.FileRequest;
|
||||
import io.metersphere.sdk.util.*;
|
||||
import io.metersphere.system.config.MinioProperties;
|
||||
import io.metersphere.system.domain.TestResourcePool;
|
||||
|
@ -36,16 +39,22 @@ import io.metersphere.system.service.TestResourcePoolService;
|
|||
import io.metersphere.system.utils.TaskRunnerClient;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.jmeter.util.JMeterUtils;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -185,6 +194,9 @@ public class ApiExecuteService {
|
|||
String endpoint = TaskRunnerClient.getEndpoint(testResourceNodeDTO.getIp(), testResourceNodeDTO.getPort());
|
||||
LogUtils.info(String.format("开始发送请求【 %s 】到 %s 节点执行", testId, endpoint), reportId);
|
||||
TaskRunnerClient.debugApi(endpoint, taskRequest);
|
||||
// 清空mino和kafka配置信息,避免前端获取
|
||||
taskRequest.setMinioConfig(null);
|
||||
taskRequest.setKafkaConfig(null);
|
||||
return taskRequest;
|
||||
} catch (Exception e) {
|
||||
LogUtils.error(e);
|
||||
|
@ -273,7 +285,7 @@ public class ApiExecuteService {
|
|||
List<ApiExecuteFileInfo> refFiles = fileAssociationService.getFiles(request.getId()).
|
||||
stream()
|
||||
.map(file -> {
|
||||
ApiExecuteFileInfo refFileInfo = getApiExecuteFileInfo(file.getFileId(), file.getFileName(),
|
||||
ApiExecuteFileInfo refFileInfo = getApiExecuteFileInfo(file.getFileId(), file.getOriginalName(),
|
||||
file.getProjectId(), file.getStorage());
|
||||
if (StorageType.isGit(file.getStorage())) {
|
||||
// 设置Git信息
|
||||
|
@ -286,7 +298,6 @@ public class ApiExecuteService {
|
|||
// 没有保存的本地临时文件
|
||||
List<String> uploadFileIds = request.getUploadFileIds();
|
||||
if (CollectionUtils.isNotEmpty(uploadFileIds)) {
|
||||
// 去掉文件管理的文件,即通过本地上传的临时文件
|
||||
List<ApiExecuteFileInfo> localTempFiles = uploadFileIds.stream()
|
||||
.map(tempFileId -> {
|
||||
String fileName = apiFileResourceService.getTempFileNameByFileId(tempFileId);
|
||||
|
@ -299,40 +310,15 @@ public class ApiExecuteService {
|
|||
List<String> linkFileIds = request.getLinkFileIds();
|
||||
// 没有保存的文件管理临时文件
|
||||
if (CollectionUtils.isNotEmpty(linkFileIds)) {
|
||||
List<ApiExecuteFileInfo> refTempFiles = fileMetadataService.getByFileIds(linkFileIds)
|
||||
.stream()
|
||||
.map(file -> {
|
||||
String fileName = file.getName();
|
||||
if (StringUtils.isNotBlank(file.getType())) {
|
||||
fileName += "." + file.getType();
|
||||
}
|
||||
ApiExecuteFileInfo tempFileInfo = getApiExecuteFileInfo(file.getId(), fileName,
|
||||
file.getProjectId(), file.getStorage());
|
||||
if (StorageType.isGit(file.getStorage())) {
|
||||
// 设置Git信息
|
||||
tempFileInfo.setFileMetadataRepositoryDTO(fileManagementService.getFileMetadataRepositoryDTO(file.getId()));
|
||||
tempFileInfo.setFileModuleRepositoryDTO(fileManagementService.getFileModuleRepositoryDTO(file.getModuleId()));
|
||||
}
|
||||
return tempFileInfo;
|
||||
}).toList();
|
||||
List<FileMetadata> fileMetadataList = fileMetadataService.getByFileIds(linkFileIds);
|
||||
// 添加临时的文件管理的文件
|
||||
refFiles.addAll(refTempFiles);
|
||||
refFiles.addAll(getApiExecuteFileInfo(fileMetadataList));
|
||||
}
|
||||
|
||||
taskRequest.setRefFiles(refFiles);
|
||||
// 获取函数jar包
|
||||
List<FileMetadata> fileMetadataList = fileManagementService.findJarByProjectId(List.of(taskRequest.getProjectId()));
|
||||
taskRequest.setFuncJars(fileMetadataList.stream()
|
||||
.map(file -> {
|
||||
String fileName = file.getOriginalName();
|
||||
ApiExecuteFileInfo tempFileInfo = getApiExecuteFileInfo(file.getId(), fileName, file.getProjectId(), file.getStorage());
|
||||
if (StorageType.isGit(file.getStorage())) {
|
||||
// 设置Git信息
|
||||
tempFileInfo.setFileMetadataRepositoryDTO(fileManagementService.getFileMetadataRepositoryDTO(file.getId()));
|
||||
tempFileInfo.setFileModuleRepositoryDTO(fileManagementService.getFileModuleRepositoryDTO(file.getModuleId()));
|
||||
}
|
||||
return tempFileInfo;
|
||||
}).toList());
|
||||
taskRequest.setFuncJars(getApiExecuteFileInfo(fileMetadataList));
|
||||
|
||||
// TODO 当前项目没有包分两种情况,1 之前存在被删除,2 一直不存在
|
||||
// 为了兼容1 这种情况需要初始化一条空的数据,由执行机去做卸载
|
||||
|
@ -343,11 +329,25 @@ public class ApiExecuteService {
|
|||
}
|
||||
}
|
||||
|
||||
private static ApiExecuteFileInfo getApiExecuteFileInfo(String fileId, String fileName, String projectId) {
|
||||
private List<ApiExecuteFileInfo> getApiExecuteFileInfo(List<FileMetadata> fileMetadataList) {
|
||||
return fileMetadataList.stream()
|
||||
.map(file -> {
|
||||
ApiExecuteFileInfo tempFileInfo = getApiExecuteFileInfo(file.getId(), file.getOriginalName(),
|
||||
file.getProjectId(), file.getStorage());
|
||||
if (StorageType.isGit(file.getStorage())) {
|
||||
// 设置Git信息
|
||||
tempFileInfo.setFileMetadataRepositoryDTO(fileManagementService.getFileMetadataRepositoryDTO(file.getId()));
|
||||
tempFileInfo.setFileModuleRepositoryDTO(fileManagementService.getFileModuleRepositoryDTO(file.getModuleId()));
|
||||
}
|
||||
return tempFileInfo;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
private ApiExecuteFileInfo getApiExecuteFileInfo(String fileId, String fileName, String projectId) {
|
||||
return getApiExecuteFileInfo(fileId, fileName, projectId, StorageType.MINIO.name());
|
||||
}
|
||||
|
||||
private static ApiExecuteFileInfo getApiExecuteFileInfo(String fileId, String fileName, String projectId, String storage) {
|
||||
private ApiExecuteFileInfo getApiExecuteFileInfo(String fileId, String fileName, String projectId, String storage) {
|
||||
ApiExecuteFileInfo apiExecuteFileInfo = new ApiExecuteFileInfo();
|
||||
apiExecuteFileInfo.setStorage(storage);
|
||||
apiExecuteFileInfo.setFileName(fileName);
|
||||
|
@ -412,4 +412,33 @@ public class ApiExecuteService {
|
|||
}
|
||||
return (String) configMap.get(ProjectApplicationType.API.API_RESOURCE_POOL_ID.name());
|
||||
}
|
||||
|
||||
public void downloadFile(String reportId, String testId, FileRequest fileRequest, HttpServletResponse response) throws Exception {
|
||||
String key = getScriptRedisKey(reportId, testId);
|
||||
if (BooleanUtils.isTrue(stringRedisTemplate.hasKey(key))) {
|
||||
FileRepository repository = StringUtils.isBlank(fileRequest.getStorage()) ? FileCenter.getDefaultRepository()
|
||||
: FileCenter.getRepository(fileRequest.getStorage());
|
||||
write2Response(repository.getFileAsStream(fileRequest), response);
|
||||
}
|
||||
}
|
||||
|
||||
public void write2Response(InputStream in, HttpServletResponse response) {
|
||||
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
|
||||
try (OutputStream out = response.getOutputStream()) {
|
||||
int len;
|
||||
byte[] bytes = new byte[1024 * 2];
|
||||
while ((len = in.read(bytes)) != -1) {
|
||||
out.write(bytes, 0, len);
|
||||
}
|
||||
out.flush();
|
||||
} catch (Exception e) {
|
||||
LogUtils.error(e);
|
||||
} finally {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
LogUtils.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,27 @@
|
|||
package io.metersphere.api.controller;
|
||||
|
||||
import io.metersphere.api.service.ApiExecuteService;
|
||||
import io.metersphere.api.service.debug.ApiDebugService;
|
||||
import io.metersphere.sdk.constants.DefaultRepositoryDir;
|
||||
import io.metersphere.sdk.constants.StorageType;
|
||||
import io.metersphere.sdk.file.FileCopyRequest;
|
||||
import io.metersphere.sdk.file.FileRequest;
|
||||
import io.metersphere.system.base.BaseTest;
|
||||
import io.metersphere.system.uid.IDGenerator;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.junit.jupiter.api.MethodOrderer;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestMethodOrder;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
|
@ -18,6 +34,13 @@ public class ApiExecuteResourceControllerTest extends BaseTest {
|
|||
|
||||
private static final String BASE_PATH = "/api/execute/resource/";
|
||||
private static final String SCRIPT = "script?reportId={0}&testId={1}";
|
||||
private static final String FILE = "file?reportId={0}&testId={1}";
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
@Resource
|
||||
private ApiExecuteService apiExecuteService;
|
||||
@Resource
|
||||
private ApiDebugService apiDebugService;
|
||||
|
||||
@Override
|
||||
public String getBasePath() {
|
||||
|
@ -28,4 +51,28 @@ public class ApiExecuteResourceControllerTest extends BaseTest {
|
|||
public void getScript() throws Exception {
|
||||
this.requestGetWithOk(SCRIPT, "reportId", "testId");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void downloadFile() throws Exception {
|
||||
String fileName = IDGenerator.nextStr() + "_file_upload.JPG";
|
||||
MockMultipartFile file = new MockMultipartFile("file", fileName, MediaType.APPLICATION_OCTET_STREAM_VALUE, "aa".getBytes());
|
||||
String fileId = apiDebugService.uploadTempFile(file);
|
||||
FileRequest fileRequest = new FileCopyRequest();
|
||||
fileRequest.setFileName(fileName);
|
||||
fileRequest.setFolder(DefaultRepositoryDir.getSystemTempDir() + "/" + fileId);
|
||||
mockMvc.perform(getPostRequestBuilder(FILE, fileRequest, "reportId", "testId"))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
String reportId = UUID.randomUUID().toString();
|
||||
String testId = UUID.randomUUID().toString();
|
||||
String scriptRedisKey = apiExecuteService.getScriptRedisKey(reportId, testId);
|
||||
stringRedisTemplate.opsForValue().set(scriptRedisKey, "aaa");
|
||||
mockMvc.perform(getPostRequestBuilder(FILE, fileRequest, reportId, testId))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
fileRequest.setStorage(StorageType.MINIO.name());
|
||||
mockMvc.perform(getPostRequestBuilder(FILE, fileRequest, reportId, testId))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,9 @@ public class FileInfo implements Serializable {
|
|||
@Schema(description = "文件名称")
|
||||
private String fileName;
|
||||
|
||||
@Schema(description = "原始文件名")
|
||||
private String originalName;
|
||||
|
||||
@Schema(description = "文件大小")
|
||||
private Long size;
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
file_association.id AS id,
|
||||
file_association.file_id AS fileId,
|
||||
CONCAT( file_metadata.`name`, IF(LENGTH(file_metadata.type) = 0, '', '.'), file_metadata.type ) AS fileName,
|
||||
file_metadata.original_name,
|
||||
file_metadata.size AS size,
|
||||
file_metadata.storage,
|
||||
file_metadata.project_id,
|
||||
|
|
Loading…
Reference in New Issue