refactor(接口测试): 接口测试执行时附件处理进行优化

接口测试执行时附件处理进行优化:文件库文件的更新日期作为文件夹、Git文件在metersphere获取
This commit is contained in:
song-tianyang 2023-02-14 15:41:08 +08:00 committed by 建国
parent 1c0b5862f6
commit fbc5408778
5 changed files with 93 additions and 41 deletions

View File

@ -120,11 +120,11 @@ public class ApiFileUtil extends FileUtils {
temporaryFileUtil = CommonBeanFactory.getBean(TemporaryFileUtil.class); temporaryFileUtil = CommonBeanFactory.getBean(TemporaryFileUtil.class);
} }
List<AttachmentBodyFile> fileList = new ArrayList<>(); List<AttachmentBodyFile> fileList = new ArrayList<>();
formatFilePathForNode(tree, reportId, isLocal, fileList); formatFilePath(tree, reportId, isLocal, fileList);
return fileList; return fileList;
} }
private static void formatFilePathForNode(HashTree tree, String reportId, boolean isLocal, List<AttachmentBodyFile> fileList) { private static void formatFilePath(HashTree tree, String reportId, boolean isLocal, List<AttachmentBodyFile> fileList) {
if (tree != null) { if (tree != null) {
if (fileMetadataService == null) { if (fileMetadataService == null) {
fileMetadataService = CommonBeanFactory.getBean(FileMetadataService.class); fileMetadataService = CommonBeanFactory.getBean(FileMetadataService.class);
@ -143,7 +143,7 @@ public class ApiFileUtil extends FileUtils {
getAttachmentBodyFileByKeystoreConfig(key, fileList); getAttachmentBodyFileByKeystoreConfig(key, fileList);
} }
if (node != null) { if (node != null) {
formatFilePathForNode(node, reportId, isLocal, fileList); formatFilePath(node, reportId, isLocal, fileList);
} }
} }
} }
@ -214,9 +214,6 @@ public class ApiFileUtil extends FileUtils {
testElement.setProperty(JmxFileMetadataColumns.REF_FILE_NAME.name(), fileMetadata.getName()); testElement.setProperty(JmxFileMetadataColumns.REF_FILE_NAME.name(), fileMetadata.getName());
testElement.setProperty(JmxFileMetadataColumns.REF_FILE_UPDATE_TIME.name(), fileMetadata.getUpdateTime()); testElement.setProperty(JmxFileMetadataColumns.REF_FILE_UPDATE_TIME.name(), fileMetadata.getUpdateTime());
testElement.setProperty(JmxFileMetadataColumns.REF_FILE_PROJECT_ID.name(), fileMetadata.getProjectId()); testElement.setProperty(JmxFileMetadataColumns.REF_FILE_PROJECT_ID.name(), fileMetadata.getProjectId());
if (StringUtils.isNotBlank(fileMetadata.getAttachInfo())) {
testElement.setProperty(JmxFileMetadataColumns.REF_FILE_ATTACH_INFO.name(), fileMetadata.getAttachInfo());
}
} else { } else {
path = temporaryFileUtil.generateFilePath(attachmentBodyFile.getProjectId(), attachmentBodyFile.getFileUpdateTime(), attachmentBodyFile.getName()); path = temporaryFileUtil.generateFilePath(attachmentBodyFile.getProjectId(), attachmentBodyFile.getFileUpdateTime(), attachmentBodyFile.getName());
} }

View File

@ -15,6 +15,7 @@ import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.constants.PluginScenario; import io.metersphere.commons.constants.PluginScenario;
import io.metersphere.commons.utils.*; import io.metersphere.commons.utils.*;
import io.metersphere.dto.AttachmentBodyFile; import io.metersphere.dto.AttachmentBodyFile;
import io.metersphere.dto.FileInfoDTO;
import io.metersphere.dto.JmeterRunRequestDTO; import io.metersphere.dto.JmeterRunRequestDTO;
import io.metersphere.dto.ProjectJarConfig; import io.metersphere.dto.ProjectJarConfig;
import io.metersphere.environment.service.BaseEnvGroupProjectService; import io.metersphere.environment.service.BaseEnvGroupProjectService;
@ -25,6 +26,7 @@ import io.metersphere.metadata.vo.RemoteFileAttachInfo;
import io.metersphere.request.BodyFile; import io.metersphere.request.BodyFile;
import io.metersphere.utils.JsonUtils; import io.metersphere.utils.JsonUtils;
import io.metersphere.utils.LoggerUtil; import io.metersphere.utils.LoggerUtil;
import io.metersphere.utils.TemporaryFileUtil;
import io.metersphere.vo.BooleanPool; import io.metersphere.vo.BooleanPool;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
@ -297,30 +299,56 @@ public class ApiJMeterFileService {
* @return * @return
*/ */
public byte[] zipLocalFilesToByteArray(BodyFileRequest request) { public byte[] zipLocalFilesToByteArray(BodyFileRequest request) {
LogUtil.info("开始下载执行报告为[" + request.getReportId() + "]的文件。");
Map<String, byte[]> files = new LinkedHashMap<>(); Map<String, byte[]> files = new LinkedHashMap<>();
if (CollectionUtils.isNotEmpty(request.getBodyFiles())) { if (CollectionUtils.isNotEmpty(request.getBodyFiles())) {
//获取要下载的合法文件 //获取要下载的合法文件
List<BodyFile> bodyFiles = this.getLegalFiles(request); List<BodyFile> legalFiles = this.getLegalFiles(request);
HashTreeUtil.downFile(bodyFiles, files, fileMetadataService); if (CollectionUtils.isNotEmpty(legalFiles)) {
for (BodyFile bodyFile : bodyFiles) { //区分本地文件和文件库文件
File file = new File(bodyFile.getName()); List<BodyFile> localFile = new ArrayList<>();
if (file.exists() && StringUtils.startsWith(file.getPath(), FileUtils.ROOT_DIR)) { List<String> remoteFileIdList = new ArrayList<>();
byte[] fileByte = FileUtils.fileToByte(file); legalFiles.forEach(file -> {
if (fileByte != null) { if (StringUtils.isNotEmpty(file.getRefResourceId())) {
files.put(file.getAbsolutePath(), fileByte); remoteFileIdList.add(file.getRefResourceId());
} } else {
localFile.add(file);
}
});
//下载本地文件
if (CollectionUtils.isNotEmpty(localFile)) {
HashTreeUtil.downFile(localFile, files, fileMetadataService);
}
//下载文件库文件
if (CollectionUtils.isNotEmpty(remoteFileIdList)) {
LogUtil.info("开始下载执行报告为[" + request.getReportId() + "]的文件库文件。");
List<FileInfoDTO> gitFileList = fileMetadataService.downloadApiExecuteFilesByIds(remoteFileIdList);
gitFileList.forEach(fileInfoDTO ->
files.put(StringUtils.join(
fileInfoDTO.getProjectId(),
File.separator,
fileInfoDTO.getFileLastUpdateTime(),
File.separator,
fileInfoDTO.getFileName()
), fileInfoDTO.getFileByte()));
LogUtil.info("下载到执行报告为[" + request.getReportId() + "]的文件库文件。共下载到【" + gitFileList.size() + "】个");
} }
} }
} }
Map<String, byte[]> zipFiles = new LinkedHashMap<>(); Map<String, byte[]> zipFiles = new LinkedHashMap<>();
for (Map.Entry<String, byte[]> entry : files.entrySet()) { for (Map.Entry<String, byte[]> entry : files.entrySet()) {
//去除文件路径前的body路径
String filePath = entry.getKey(); String filePath = entry.getKey();
if (StringUtils.startsWith(filePath, FileUtils.BODY_FILE_DIR + "/")) { if (StringUtils.startsWith(filePath, FileUtils.BODY_FILE_DIR + File.separator)) {
//如果路径是以bodyFileDir开头的旧文件需要去除文件路径前的body路径并放入默认文件夹中这样可以直接在/node根目录解压不用再区分是git文件还是local文件
filePath = StringUtils.substring(filePath, FileUtils.BODY_FILE_DIR.length() + 1); filePath = StringUtils.substring(filePath, FileUtils.BODY_FILE_DIR.length() + 1);
filePath = TemporaryFileUtil.DEFAULT_FILE_FOLDER + File.separator + filePath;
} }
zipFiles.put(filePath, entry.getValue()); zipFiles.put(filePath, entry.getValue());
} }
LogUtil.info("下载执行报告为[" + request.getReportId() + "]的文件结束。");
return listBytesToZip(zipFiles); return listBytesToZip(zipFiles);
} }

View File

@ -4,7 +4,6 @@ public enum JmxFileMetadataColumns {
REF_FILE_STORAGE, REF_FILE_STORAGE,
REF_FILE_UPDATE_TIME, REF_FILE_UPDATE_TIME,
REF_FILE_PROJECT_ID, REF_FILE_PROJECT_ID,
REF_FILE_ATTACH_INFO,
REF_FILE_NAME, REF_FILE_NAME,
JAR_PATH_CONFIG, JAR_PATH_CONFIG,
} }

View File

@ -27,16 +27,20 @@ public class TemporaryFileUtil {
+ File.separator; + File.separator;
} }
public String generateFileDir(String folder) { public String generateFileDir(String folder, long updateTime) {
if (StringUtils.isBlank(folder)) { if (StringUtils.isBlank(folder)) {
folder = DEFAULT_FILE_FOLDER; folder = DEFAULT_FILE_FOLDER;
} }
if (updateTime == 0) {
return fileFolder + folder + File.separator; return fileFolder + folder + File.separator;
} else {
return fileFolder + folder + File.separator + updateTime + File.separator;
}
} }
public String generateFilePath(String folder, long updateTime, String fileName) { public String generateFilePath(String folder, long updateTime, String fileName) {
String finalFileName = updateTime > 0 ? updateTime + "_" + fileName : fileName; return generateFileDir(folder, updateTime) + fileName;
return generateFileDir(folder) + finalFileName;
} }
public File getFile(String folder, long updateTime, String fileName) { public File getFile(String folder, long updateTime, String fileName) {
@ -50,7 +54,7 @@ public class TemporaryFileUtil {
public void saveFile(String folder, long updateTime, String fileName, byte[] fileBytes) { public void saveFile(String folder, long updateTime, String fileName, byte[] fileBytes) {
//删除过期文件 //删除过期文件
deleteOldFile(folder, fileName); deleteOldFile(folder, updateTime, fileName);
this.createFile(generateFilePath(folder, updateTime, fileName), fileBytes); this.createFile(generateFilePath(folder, updateTime, fileName), fileBytes);
} }
@ -58,27 +62,49 @@ public class TemporaryFileUtil {
if (fileBytes != null && StringUtils.isNotBlank(folder) && updateTime > 0 if (fileBytes != null && StringUtils.isNotBlank(folder) && updateTime > 0
&& StringUtils.isNotBlank(fileName) && fileBytes.length > 0) { && StringUtils.isNotBlank(fileName) && fileBytes.length > 0) {
//删除过期文件 //删除过期文件
deleteOldFile(folder, fileName); deleteOldFile(folder, updateTime, fileName);
this.createFile(generateFilePath(folder, updateTime, fileName), fileBytes); this.createFile(generateFilePath(folder, updateTime, fileName), fileBytes);
} }
} }
private void deleteOldFile(String folder, String deleteFileName) { //node也调用了该方法
List<String> deleteFileList = new ArrayList<>(); public void deleteOldFile(String folder, long lastUpdateTime, String deleteFileName) {
File file = new File(generateFileDir(folder)); String newFileFolderName = String.valueOf(lastUpdateTime);
if (file.exists() && file.isDirectory()) { List<File> deleteFileList = new ArrayList<>();
String[] fileNameArr = file.list(); File file = new File(generateFileDir(folder, 0));
if (fileNameArr != null) { //当前目录下存放的是以时间戳命名的文件夹文件夹里存放着具体的文件所以要删除这个
for (String fileName : fileNameArr) { if (file.isDirectory()) {
if (fileName.endsWith("_" + deleteFileName)) { File[] checkFileFolders = file.listFiles();
deleteFileList.add(fileName); if (checkFileFolders != null) {
for (File checkFileFolder : checkFileFolders) {
if (checkFileFolder.isDirectory()) {
File[] checkFiles = checkFileFolder.listFiles();
if (checkFiles != null) {
for (File checkFile : checkFiles) {
if (StringUtils.equals(checkFile.getName(), deleteFileName)
&& !StringUtils.equals(checkFileFolder.getName(), newFileFolderName)) {
//文件名称相同但是所属的时间戳文件夹与本次不相同的文件是过期文件
deleteFileList.add(checkFile);
}
}
} }
} }
} }
} }
deleteFileList.forEach(fileName -> this.deleteFile(generateFileDir(folder) + fileName));
} }
deleteFileList.forEach(deleteFile -> {
if (deleteFile.exists()) {
deleteFile.delete();
}
File deleteFileFolder = deleteFile.getParentFile();
if (deleteFileFolder.isDirectory() && deleteFileFolder.listFiles().length == 0) {
deleteFileFolder.delete();
}
});
}
//勿删 这段代码在node中会用到
public byte[] fileToByte(File tradeFile) { public byte[] fileToByte(File tradeFile) {
byte[] buffer = null; byte[] buffer = null;
try (FileInputStream fis = new FileInputStream(tradeFile); try (FileInputStream fis = new FileInputStream(tradeFile);
@ -98,7 +124,7 @@ public class TemporaryFileUtil {
private void createFile(String filePath, byte[] fileBytes) { private void createFile(String filePath, byte[] fileBytes) {
File file = new File(filePath); File file = new File(filePath);
if (file.exists()) { if (file.exists()) {
this.deleteFile(filePath); file.delete();
} }
try { try {
File dir = file.getParentFile(); File dir = file.getParentFile();
@ -120,11 +146,4 @@ public class TemporaryFileUtil {
LoggerUtil.error(e); LoggerUtil.error(e);
} }
} }
public void deleteFile(String path) {
File file = new File(path);
if (file.exists()) {
file.delete();
}
}
} }

View File

@ -680,4 +680,13 @@ public class FileMetadataService {
return newMetadata; return newMetadata;
} }
public List<FileMetadataWithBLOBs> getFileMetadataByIdList(List<String> fileMetadataIdList) {
if (CollectionUtils.isNotEmpty(fileMetadataIdList)) {
FileMetadataExample example = new FileMetadataExample();
example.createCriteria().andIdIn(fileMetadataIdList);
return fileMetadataMapper.selectByExampleWithBLOBs(example);
} else {
return new ArrayList<>();
}
}
} }