fix(接口测试): 场景引用csv,文件管理更新文件版本后,不生效

--bug=1045399 --user=陈建星 【接口测试】-场景CSV参数中使用文件库中的csv,在文件更换后,执行场景,场景无法读取到csv文件中的参数 https://www.tapd.cn/55049933/s/1581080
This commit is contained in:
AgAngle 2024-09-20 18:43:25 +08:00 committed by Craftsman
parent b5a506438b
commit e2e4d9b1d8
4 changed files with 135 additions and 16 deletions

View File

@ -42,6 +42,9 @@ public class ApiFileAssociationUpdateService implements FileAssociationUpdateSer
case FileAssociationSourceUtil.SOURCE_TYPE_API_SCENARIO_STEP -> case FileAssociationSourceUtil.SOURCE_TYPE_API_SCENARIO_STEP ->
Objects.requireNonNull(CommonBeanFactory.getBean(ApiScenarioService.class)) Objects.requireNonNull(CommonBeanFactory.getBean(ApiScenarioService.class))
.handleStepFileAssociationUpgrade(originFileAssociation, newFileMetadata); .handleStepFileAssociationUpgrade(originFileAssociation, newFileMetadata);
case FileAssociationSourceUtil.SOURCE_TYPE_API_SCENARIO ->
Objects.requireNonNull(CommonBeanFactory.getBean(ApiScenarioService.class))
.handleScenarioFileAssociationUpgrade(originFileAssociation, newFileMetadata);
default -> { default -> {
} }
} }

View File

@ -102,6 +102,10 @@ public class ApiScenarioRunService {
msScenario.setScenarioConfig(getScenarioConfig(request, true)); msScenario.setScenarioConfig(getScenarioConfig(request, true));
msScenario.setProjectId(request.getProjectId()); msScenario.setProjectId(request.getProjectId());
List<ApiScenarioCsv> dbCsv = apiScenarioService.getApiScenarioCsv(apiScenario.getId());
List<CsvVariable> csvVariables = apiScenarioService.getCsvVariables(msScenario.getScenarioConfig());
apiScenarioService.handleRefUpgradeFile(csvVariables, dbCsv);
// 处理特殊的步骤详情 // 处理特殊的步骤详情
apiScenarioService.addSpecialStepDetails(request.getSteps(), request.getStepDetails()); apiScenarioService.addSpecialStepDetails(request.getSteps(), request.getStepDetails());
@ -376,6 +380,10 @@ public class ApiScenarioRunService {
msScenario.setProjectId(request.getProjectId()); msScenario.setProjectId(request.getProjectId());
msScenario.setResourceId(request.getId()); msScenario.setResourceId(request.getId());
List<ApiScenarioCsv> dbCsv = apiScenarioService.getApiScenarioCsv(apiScenario.getId());
List<CsvVariable> csvVariables = apiScenarioService.getCsvVariables(msScenario.getScenarioConfig());
apiScenarioService.handleRefUpgradeFile(csvVariables, dbCsv);
// 处理特殊的步骤详情 // 处理特殊的步骤详情
apiScenarioService.addSpecialStepDetails(request.getSteps(), request.getStepDetails()); apiScenarioService.addSpecialStepDetails(request.getSteps(), request.getStepDetails());

View File

@ -26,12 +26,10 @@ import io.metersphere.api.utils.ApiScenarioBatchOperationUtils;
import io.metersphere.functional.domain.FunctionalCaseTestExample; import io.metersphere.functional.domain.FunctionalCaseTestExample;
import io.metersphere.functional.mapper.FunctionalCaseTestMapper; import io.metersphere.functional.mapper.FunctionalCaseTestMapper;
import io.metersphere.plugin.api.spi.AbstractMsTestElement; import io.metersphere.plugin.api.spi.AbstractMsTestElement;
import io.metersphere.project.domain.FileAssociation; import io.metersphere.project.domain.*;
import io.metersphere.project.domain.FileMetadata;
import io.metersphere.project.domain.Project;
import io.metersphere.project.domain.ProjectExample;
import io.metersphere.project.dto.MoveNodeSortDTO; import io.metersphere.project.dto.MoveNodeSortDTO;
import io.metersphere.project.mapper.ExtBaseProjectVersionMapper; import io.metersphere.project.mapper.ExtBaseProjectVersionMapper;
import io.metersphere.project.mapper.FileMetadataMapper;
import io.metersphere.project.mapper.ProjectMapper; import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.project.service.MoveNodeService; import io.metersphere.project.service.MoveNodeService;
import io.metersphere.sdk.constants.*; import io.metersphere.sdk.constants.*;
@ -138,6 +136,8 @@ public class ApiScenarioService extends MoveNodeService {
@Resource @Resource
private ApiScenarioCsvMapper apiScenarioCsvMapper; private ApiScenarioCsvMapper apiScenarioCsvMapper;
@Resource @Resource
private FileMetadataMapper fileMetadataMapper;
@Resource
private ApiScenarioCsvStepMapper apiScenarioCsvStepMapper; private ApiScenarioCsvStepMapper apiScenarioCsvStepMapper;
@Resource @Resource
private ScheduleService scheduleService; private ScheduleService scheduleService;
@ -508,10 +508,10 @@ public class ApiScenarioService extends MoveNodeService {
handleCsvDataUpdate(csvVariables, scenario, List.of()); handleCsvDataUpdate(csvVariables, scenario, List.of());
// 处理文件的上传 // 处理文件的上传
handleCsvFileUpdate(csvVariables, List.of(), scenario, creator); handleCsvFileAdd(csvVariables, List.of(), scenario, creator);
} }
private List<CsvVariable> getCsvVariables(ScenarioConfig scenarioConfig) { public List<CsvVariable> getCsvVariables(ScenarioConfig scenarioConfig) {
if (scenarioConfig == null || scenarioConfig.getVariable() == null || scenarioConfig.getVariable().getCsvVariables() == null) { if (scenarioConfig == null || scenarioConfig.getVariable() == null || scenarioConfig.getVariable().getCsvVariables() == null) {
return List.of(); return List.of();
} }
@ -569,18 +569,90 @@ public class ApiScenarioService extends MoveNodeService {
List<CsvVariable> csvVariables = getCsvVariables(scenarioConfig); List<CsvVariable> csvVariables = getCsvVariables(scenarioConfig);
List<ApiScenarioCsv> dbCsv = getApiScenarioCsv(scenario.getId()); List<ApiScenarioCsv> dbCsv = getApiScenarioCsv(scenario.getId());
List<String> dbCsvIds = dbCsv.stream()
.map(ApiScenarioCsv::getId)
.toList();
handleRefUpgradeFile(csvVariables, dbCsv);
// 更新 csv 相关数据表 // 更新 csv 相关数据表
handleCsvDataUpdate(csvVariables, scenario, dbCsv); handleCsvDataUpdate(csvVariables, scenario, dbCsvIds);
// 处理文件的上传和删除 // 处理文件的上传和删除
handleCsvFileUpdate(csvVariables, dbCsv, scenario, userId); handleCsvFileUpdate(csvVariables, dbCsv, scenario, userId);
} }
private void handleCsvDataUpdate(List<CsvVariable> csvVariables, ApiScenario scenario, List<ApiScenarioCsv> dbCsv) { /**
List<String> dbCsvIds = dbCsv.stream() * 当文件管理更新了关联资源的 csv 文件版本时
.map(ApiScenarioCsv::getId) * 前端文件并未更新这里使用时进行对比使用较新的文件版本
.toList(); * @param csvVariables
* @param dbCsv
*/
public void handleRefUpgradeFile(List<CsvVariable> csvVariables, List<ApiScenarioCsv> dbCsv) {
try {
// 获取数据库中关联的 csv 文件
List<ApiScenarioCsv> dbAssociationCsvList = dbCsv.stream().filter(ApiScenarioCsv::getAssociation).toList();
Map<String, ApiScenarioCsv> dbAssociationCsvIdMap = dbAssociationCsvList.stream()
.collect(Collectors.toMap(ApiScenarioCsv::getId, Function.identity()));
// 获取与数据库中数据 fileId 不一致的 csv
List<CsvVariable> changeAssociationCsvList = csvVariables.stream().filter(csvVariable -> {
ApiScenarioCsv apiScenarioCsv = dbAssociationCsvIdMap.get(csvVariable.getId());
if (apiScenarioCsv != null && csvVariable.getFile() != null && StringUtils.isNotBlank(csvVariable.getFile().getFileId())
&& !StringUtils.equals(apiScenarioCsv.getFileId(), csvVariable.getFile().getFileId())) {
return true;
}
return false;
}).toList();
if (CollectionUtils.isEmpty(changeAssociationCsvList)) {
return;
}
// 查询关联的csv文件信息
List<String> dbAssociationCsvFileIds = changeAssociationCsvList.stream().map(csvVariable -> csvVariable.getFile().getFileId()).toList();
FileMetadataExample fileMetadataExample = new FileMetadataExample();
fileMetadataExample.createCriteria().andIdIn(dbAssociationCsvFileIds);
List<FileMetadata> dbAssociationCsvFiles = fileMetadataMapper.selectByExample(fileMetadataExample);
Map<String, FileMetadata> dbAssociationCsvFileMap = dbAssociationCsvFiles.stream()
.collect(Collectors.toMap(FileMetadata::getId, Function.identity()));
// 查询csv文件的版本信息
List<String> refIds = dbAssociationCsvFiles.stream().map(FileMetadata::getRefId).toList();
FileMetadataExample example = new FileMetadataExample();
example.createCriteria().andRefIdIn(refIds);
List<FileMetadata> fileMetadataList = fileMetadataMapper.selectByExample(example)
.stream()
.sorted(Comparator.comparing(FileMetadata::getUpdateTime).reversed())
.collect(Collectors.toList());
Map<String, List<FileMetadata>> refFileMap = fileMetadataList.stream().collect(Collectors.groupingBy(FileMetadata::getRefId));
for (CsvVariable changeAssociation : changeAssociationCsvList) {
String fileId = changeAssociation.getFile().getFileId();
FileMetadata fileMetadata = dbAssociationCsvFileMap.get(fileId);
ApiScenarioCsv dbAssociationCsv = dbAssociationCsvIdMap.get(changeAssociation.getId());
// 遍历同一文件的不同版本
List<FileMetadata> refFileList = refFileMap.get(fileMetadata.getRefId());
if (refFileList != null) {
for (FileMetadata refFile : refFileList) {
if (StringUtils.equals(refFile.getId(), fileId)) {
// 如果前端参数的版本较新则不处理
break;
} else if (StringUtils.equals(refFile.getId(), dbAssociationCsv.getFileId())) {
// 如果数据库中的文件版本较新则说明文件管理中更新了当前引用的文件版本使用数据库中的文件信息
changeAssociation.getFile().setFileId(dbAssociationCsv.getFileId());
changeAssociation.getFile().setFileName(dbAssociationCsv.getFileName());
break;
}
}
}
}
} catch (Exception e) {
LogUtils.error(e);
}
}
private void handleCsvDataUpdate(List<CsvVariable> csvVariables, ApiScenario scenario, List<String> dbCsvIds) {
List<String> csvIds = csvVariables.stream() List<String> csvIds = csvVariables.stream()
.map(CsvVariable::getId) .map(CsvVariable::getId)
@ -616,7 +688,7 @@ public class ApiScenarioService extends MoveNodeService {
} }
} }
private void handleCsvFileUpdate(List<CsvVariable> csvVariables, List<ApiScenarioCsv> dbCsv, ApiScenario scenario, String userId) { private void handleCsvFileAdd(List<CsvVariable> csvVariables, List<ApiScenarioCsv> dbCsv, ApiScenario scenario, String userId) {
ApiFileResourceUpdateRequest resourceUpdateRequest = getApiFileResourceUpdateRequest(scenario.getId(), scenario.getProjectId(), userId); ApiFileResourceUpdateRequest resourceUpdateRequest = getApiFileResourceUpdateRequest(scenario.getId(), scenario.getProjectId(), userId);
// 设置本地文件相关参数 // 设置本地文件相关参数
setCsvLocalFileParam(csvVariables, dbCsv, resourceUpdateRequest); setCsvLocalFileParam(csvVariables, dbCsv, resourceUpdateRequest);
@ -625,17 +697,26 @@ public class ApiScenarioService extends MoveNodeService {
apiFileResourceService.addFileResource(resourceUpdateRequest); apiFileResourceService.addFileResource(resourceUpdateRequest);
} }
private void handleCsvFileUpdate(List<CsvVariable> csvVariables, List<ApiScenarioCsv> dbCsv, ApiScenario scenario, String userId) {
ApiFileResourceUpdateRequest resourceUpdateRequest = getApiFileResourceUpdateRequest(scenario.getId(), scenario.getProjectId(), userId);
// 设置本地文件相关参数
setCsvLocalFileParam(csvVariables, dbCsv, resourceUpdateRequest);
// 设置关联文件相关参数
setCsvLinkFileParam(csvVariables, dbCsv, resourceUpdateRequest);
apiFileResourceService.updateFileResource(resourceUpdateRequest);
}
private void setCsvLinkFileParam(List<CsvVariable> csvVariables, List<ApiScenarioCsv> dbCsv, ApiFileResourceUpdateRequest resourceUpdateRequest) { private void setCsvLinkFileParam(List<CsvVariable> csvVariables, List<ApiScenarioCsv> dbCsv, ApiFileResourceUpdateRequest resourceUpdateRequest) {
// 获取数据库中关联的文件id // 获取数据库中关联的文件id
List<String> dbRefFileIds = dbCsv.stream() List<String> dbRefFileIds = dbCsv.stream()
.filter(c -> BooleanUtils.isTrue(c.getAssociation())) .filter(c -> BooleanUtils.isTrue(c.getAssociation()) && StringUtils.isNotBlank(c.getFileId()))
.map(ApiScenarioCsv::getFileId) .map(ApiScenarioCsv::getFileId)
.toList(); .toList();
// 获取请求中关联的文件id // 获取请求中关联的文件id
List<String> refFileIds = csvVariables.stream() List<String> refFileIds = csvVariables.stream()
.map(CsvVariable::getFile) .map(CsvVariable::getFile)
.filter(c -> BooleanUtils.isFalse(c.getLocal())) .filter(c -> BooleanUtils.isFalse(c.getLocal()) && StringUtils.isNotBlank(c.getFileId()))
.map(ApiFile::getFileId).toList(); .map(ApiFile::getFileId).toList();
List<String> unlinkFileIds = ListUtils.subtract(dbRefFileIds, refFileIds); List<String> unlinkFileIds = ListUtils.subtract(dbRefFileIds, refFileIds);
@ -665,7 +746,7 @@ public class ApiScenarioService extends MoveNodeService {
resourceUpdateRequest.setUploadFileIds(addLocal); resourceUpdateRequest.setUploadFileIds(addLocal);
} }
private List<ApiScenarioCsv> getApiScenarioCsv(String scenarioId) { public List<ApiScenarioCsv> getApiScenarioCsv(String scenarioId) {
ApiScenarioCsvExample apiScenarioCsvExample = new ApiScenarioCsvExample(); ApiScenarioCsvExample apiScenarioCsvExample = new ApiScenarioCsvExample();
apiScenarioCsvExample.createCriteria().andScenarioIdEqualTo(scenarioId); apiScenarioCsvExample.createCriteria().andScenarioIdEqualTo(scenarioId);
return apiScenarioCsvMapper.selectByExample(apiScenarioCsvExample); return apiScenarioCsvMapper.selectByExample(apiScenarioCsvExample);
@ -2284,7 +2365,7 @@ public class ApiScenarioService extends MoveNodeService {
} catch (Exception e) { } catch (Exception e) {
LogUtils.error(e); LogUtils.error(e);
} }
if (msTestElement instanceof MsHTTPElement msHTTPElement) { if (msTestElement != null && msTestElement instanceof MsHTTPElement msHTTPElement) {
List<ApiFile> updateFiles = apiCommonService.getApiFilesByFileId(originFileAssociation.getFileId(), msHTTPElement); List<ApiFile> updateFiles = apiCommonService.getApiFilesByFileId(originFileAssociation.getFileId(), msHTTPElement);
// 替换文件的Id和name // 替换文件的Id和name
apiCommonService.replaceApiFileInfo(updateFiles, newFileMetadata); apiCommonService.replaceApiFileInfo(updateFiles, newFileMetadata);
@ -2296,6 +2377,31 @@ public class ApiScenarioService extends MoveNodeService {
} }
} }
public void handleScenarioFileAssociationUpgrade(FileAssociation originFileAssociation, FileMetadata newFileMetadata) {
String scenarioId = originFileAssociation.getSourceId();
// 查询步骤详情
ApiScenarioBlob apiScenarioBlob = apiScenarioBlobMapper.selectByPrimaryKey(originFileAssociation.getSourceId());
if (apiScenarioBlob == null || apiScenarioBlob.getConfig() == null) {
return;
}
List<CsvVariable> csvVariables = getCsvVariables(scenarioId);
List<ApiFile> updateFiles = new ArrayList<>(csvVariables.size());
for (CsvVariable csvVariable : csvVariables) {
ApiFile apiFile = csvVariable.getFile();
if (apiFile != null && StringUtils.equals(originFileAssociation.getFileId(), apiFile.getFileId())) {
updateFiles.add(apiFile);
}
}
if (CollectionUtils.isNotEmpty(updateFiles)) {
// 替换文件的Id和name
apiCommonService.replaceApiFileInfo(updateFiles, newFileMetadata);
List<String> dbCsvIds = csvVariables.stream().map(CsvVariable::getId).toList();
handleCsvDataUpdate(csvVariables, apiScenarioMapper.selectByPrimaryKey(originFileAssociation.getSourceId()), dbCsvIds);
}
}
public String scenarioTransfer(ApiTransferRequest request, String userId) { public String scenarioTransfer(ApiTransferRequest request, String userId) {
String apiScenarioStepDir = DefaultRepositoryDir.getApiScenarioDir(request.getProjectId(), request.getSourceId()); String apiScenarioStepDir = DefaultRepositoryDir.getApiScenarioDir(request.getProjectId(), request.getSourceId());
return apiFileResourceService.transfer(request, userId, apiScenarioStepDir); return apiFileResourceService.transfer(request, userId, apiScenarioStepDir);

View File

@ -643,6 +643,8 @@ public class ApiScenarioControllerTests extends BaseTest {
request.setPriority("P0 update"); request.setPriority("P0 update");
request.setStatus(ApiScenarioStatus.DEPRECATED.name()); request.setStatus(ApiScenarioStatus.DEPRECATED.name());
List<ApiScenarioStepRequest> steps = getApiScenarioStepRequests(); List<ApiScenarioStepRequest> steps = getApiScenarioStepRequests();
ApiScenarioBlob apiScenarioBlob = apiScenarioBlobMapper.selectByPrimaryKey(addApiScenario.getId());
request.setScenarioConfig(JSON.parseObject(new String(apiScenarioBlob.getConfig()), ScenarioConfig.class));
// 验证修改基础信息 // 验证修改基础信息
this.requestPostWithOk(DEFAULT_UPDATE, request); this.requestPostWithOk(DEFAULT_UPDATE, request);