refactor(接口测试): 将查询变更记录放到xpack

This commit is contained in:
wxg0103 2024-01-27 14:59:46 +08:00 committed by wxg0103
parent efbafded61
commit dc2a4efec9
14 changed files with 215 additions and 113 deletions

View File

@ -202,7 +202,7 @@ public class ApiDefinitionController {
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_IMPORT)
@Operation(summary = "接口测试-接口管理-导入接口定义")
public ApiDefinitionImport testCaseImport(@RequestPart(value = "file", required = false) MultipartFile file, @RequestPart("request") ImportRequest request) {
return apiDefinitionService.apiTestImport(file, request, SessionUtils.getUserId(), SessionUtils.getCurrentProjectId());
return apiDefinitionService.apiTestImport(file, request, SessionUtils.getUser(), SessionUtils.getCurrentProjectId());
}
@PostMapping("/operation-history")

View File

@ -89,7 +89,7 @@ public class ApiDefinitionModuleController {
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_READ)
@CheckOwner(resourceId = "#request.projectId", resourceType = "project")
public List<BaseTreeNode> getTrashTree(@RequestBody @Validated ApiModuleRequest request) {
return apiDefinitionModuleService.getTrashTree(request, true);
return apiDefinitionModuleService.getTrashTree(request);
}
@PostMapping("/env/tree")

View File

@ -216,7 +216,7 @@ public class ApiTestCaseController {
public Pager<List<OperationHistoryDTO>> operationHistoryList(@Validated @RequestBody OperationHistoryRequest request) {
Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize(),
StringUtils.isNotBlank(request.getSortString()) ? request.getSortString() : "create_time desc");
return PageUtils.setPageInfo(page, apiTestCaseService.getHistoryList(request));
return PageUtils.setPageInfo(page, apiTestCaseService.operationHistoryList(request));
}

View File

@ -14,7 +14,7 @@ public class ImportRequest {
private String projectId;
@Schema(description = "导入的swagger地址")
private String swaggerUrl;
@Schema(description = "如果是定时任务的时候 需要传入创建人id")
@Schema(description = "如果是定时任务的时候 需要传入创建人id", requiredMode = Schema.RequiredMode.REQUIRED)
private String userId;
private String versionId; // 新导入选择的版本
private String updateVersionId; // 覆盖导入已存在的接口选择的版本

View File

@ -14,7 +14,6 @@ import io.metersphere.api.utils.ApiDataUtils;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.LogUtils;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.utils.SessionUtils;
import io.swagger.parser.OpenAPIParser;
import io.swagger.v3.oas.models.*;
import io.swagger.v3.oas.models.media.*;
@ -283,11 +282,7 @@ public class Swagger3Parser<T> implements ImportParser<ApiDefinitionImport> {
apiDefinition.setProtocol("HTTP");
apiDefinition.setMethod(method);
apiDefinition.setProjectId(this.projectId);
if (StringUtils.equalsIgnoreCase("schedule", importRequest.getType())) {
apiDefinition.setCreateUser(importRequest.getUserId());
} else {
apiDefinition.setCreateUser(SessionUtils.getUserId());
}
apiDefinition.setModulePath(CollectionUtils.isNotEmpty(operation.getTags()) ? StringUtils.join("/", operation.getTags().get(0)) : StringUtils.EMPTY);
apiDefinition.setResponse(new ArrayList<>());
return apiDefinition;
@ -622,6 +617,9 @@ public class Swagger3Parser<T> implements ImportParser<ApiDefinitionImport> {
} else {
itemsSchema = items;
}
if (itemsSchema == null) {
return jsonSchemaArray;
}
if (itemsSchema instanceof IntegerSchema integerSchema) {
jsonSchemaArray.setItems(parseInteger(integerSchema));
} else if (itemsSchema instanceof StringSchema stringSchema) {

View File

@ -34,11 +34,15 @@ import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.dto.sdk.ApiDefinitionCaseDTO;
import io.metersphere.system.dto.sdk.BaseTreeNode;
import io.metersphere.system.dto.sdk.SessionUser;
import io.metersphere.system.log.constants.OperationLogModule;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.log.dto.LogDTO;
import io.metersphere.system.log.service.OperationLogService;
import io.metersphere.system.notice.constants.NoticeConstants;
import io.metersphere.system.notice.sender.AfterReturningNoticeSendService;
import io.metersphere.system.uid.IDGenerator;
import io.metersphere.system.uid.NumGenerator;
import jakarta.annotation.Resource;
@ -60,7 +64,6 @@ import java.util.stream.Collectors;
public class ApiDefinitionImportUtilService {
private static final String UNPLANNED_API = "api_unplanned_request";
private static final String MODULE = "modulePath";
public static final Long ORDER_STEP = 5000L;
private final ThreadLocal<Long> currentApiOrder = new ThreadLocal<>();
private final ThreadLocal<Long> currentApiCaseOrder = new ThreadLocal<>();
@ -78,33 +81,37 @@ public class ApiDefinitionImportUtilService {
@Resource
private ApiDefinitionBlobMapper apiDefinitionBlobMapper;
@Resource
private ApiTestCaseService apiTestCaseService;
@Resource
private ApiDefinitionModuleService apiDefinitionModuleService;
@Resource
private ProjectMapper projectMapper;
@Resource
private OperationLogService operationLogService;
@Resource
private AfterReturningNoticeSendService afterReturningNoticeSendService;
private static final String FILE_JMX = "jmx";
private static final String FILE_HAR = "har";
private static final String FILE_JSON = "json";
public void checkFileSuffixName(ImportRequest request, String suffixName) {
if ("jmx".equalsIgnoreCase(suffixName)) {
if (FILE_JMX.equalsIgnoreCase(suffixName)) {
if (!ApiImportPlatform.Jmeter.name().equalsIgnoreCase(request.getPlatform())) {
throw new MSException(Translator.get("file_format_does_not_meet_requirements"));
}
}
if ("har".equalsIgnoreCase(suffixName)) {
if (FILE_HAR.equalsIgnoreCase(suffixName)) {
if (!ApiImportPlatform.Har.name().equalsIgnoreCase(request.getPlatform())) {
throw new MSException(Translator.get("file_format_does_not_meet_requirements"));
}
}
if ("json".equalsIgnoreCase(suffixName)) {
if (FILE_JSON.equalsIgnoreCase(suffixName)) {
if (ApiImportPlatform.Har.name().equalsIgnoreCase(request.getPlatform()) || ApiImportPlatform.Jmeter.name().equalsIgnoreCase(request.getPlatform())) {
throw new MSException(Translator.get("file_format_does_not_meet_requirements"));
}
}
}
public void importApi(ImportRequest request, ApiDefinitionImport apiImport) {
public void importApi(ImportRequest request, ApiDefinitionImport apiImport, SessionUser user) {
String defaultVersion = extBaseProjectVersionMapper.getDefaultVersion(request.getProjectId());
request.setDefaultVersion(defaultVersion);
if (request.getVersionId() == null) {
@ -126,11 +133,11 @@ public class ApiDefinitionImportUtilService {
}
//处理数据判断数据是否重复
dealWithData(request, filterData);
dealWithData(request, filterData, user);
}
private void dealWithData(ImportRequest request, List<ApiDefinitionImportDTO> importData) {
private void dealWithData(ImportRequest request, List<ApiDefinitionImportDTO> importData, SessionUser user) {
//查询数据库中所有的数据 用于判断是否重复
ApiDefinitionPageRequest pageRequest = new ApiDefinitionPageRequest();
pageRequest.setProjectId(request.getProjectId());
@ -139,12 +146,12 @@ public class ApiDefinitionImportUtilService {
List<ApiDefinitionImportDTO> apiLists = extApiDefinitionMapper.importList(pageRequest);
List<BaseTreeNode> apiModules = this.buildTreeData(request.getProjectId(), request.getProtocol());
//将apiModules转换成新的map 要求key是attachInfo中的modulePath 使用stream实现
Map<String, BaseTreeNode> modulePathMap = apiModules.stream().collect(Collectors.toMap(t -> t.getAttachInfo().get(MODULE), t -> t));
Map<String, BaseTreeNode> modulePathMap = apiModules.stream().collect(Collectors.toMap(BaseTreeNode::getPath, t -> t));
Map<String, BaseTreeNode> idModuleMap = apiModules.stream().collect(Collectors.toMap(BaseTreeNode::getId, apiModuleDTO -> apiModuleDTO));
//如果导入的时候选择了模块需要把所有的导入数据的模块路径前面拼接上选择的模块路径
if (StringUtils.isNotBlank(request.getModuleId())) {
BaseTreeNode baseTreeNode = idModuleMap.get(request.getModuleId());
String modulePath = baseTreeNode.getAttachInfo().get(MODULE);
String modulePath = baseTreeNode.getPath();
importData.forEach(t -> {
t.setModulePath(modulePath + t.getModulePath());
});
@ -152,7 +159,7 @@ public class ApiDefinitionImportUtilService {
//去掉apiLists中不存在的模块数据
apiLists = apiLists.stream().filter(t -> modulePathMap.containsKey(t.getModulePath())).toList();
apiLists.forEach(t -> {
t.setModulePath(idModuleMap.get(t.getModuleId()) != null ? idModuleMap.get(t.getModuleId()).getAttachInfo().get(MODULE) : StringUtils.EMPTY);
t.setModulePath(idModuleMap.get(t.getModuleId()) != null ? idModuleMap.get(t.getModuleId()).getPath() : StringUtils.EMPTY);
});
ApiDeatlWithData apiDeatlWithData = new ApiDeatlWithData();
//判断数据是否是唯一的
@ -162,7 +169,7 @@ public class ApiDefinitionImportUtilService {
getNeedUpdateData(request, apiDeatlWithData, apiDeatlWithDataUpdate);
//数据入库
insertData(modulePathMap, idModuleMap, apiDeatlWithDataUpdate, request);
insertData(modulePathMap, idModuleMap, apiDeatlWithDataUpdate, request, user);
}
@ -181,7 +188,7 @@ public class ApiDefinitionImportUtilService {
return order;
}
public Long getImportNextCaseOrder(String projectId) {
/* public Long getImportNextCaseOrder(String projectId) {
Long order = currentApiCaseOrder.get();
if (order == null) {
order = apiTestCaseService.getNextOrder(projectId);
@ -189,7 +196,7 @@ public class ApiDefinitionImportUtilService {
order = order + ORDER_STEP;
currentApiCaseOrder.set(order);
return order;
}
}*/
public Long getImportNextModuleOrder(String projectId) {
Long order = currentModuleOrder.get();
@ -205,7 +212,7 @@ public class ApiDefinitionImportUtilService {
public void insertData(Map<String, BaseTreeNode> modulePathMap,
Map<String, BaseTreeNode> idModuleMap,
ApiDeatlWithDataUpdate apiDeatlWithDataUpdate,
ImportRequest request) {
ImportRequest request, SessionUser user) {
//先判断是否需要新增模块
List<ApiDefinitionImportDTO> addModuleData = apiDeatlWithDataUpdate.getAddModuleData();
List<ApiDefinitionImportDTO> updateModuleData = apiDeatlWithDataUpdate.getUpdateModuleData();
@ -228,15 +235,20 @@ public class ApiDefinitionImportUtilService {
//解析modulePath 格式为/a/b/c
String[] split = item.split("/");
//一层一层的创建
for (int i = 0; i < split.length; i++) {
String path = StringUtils.join(split, "/", 0, i + 1);
for (int i = 1; i < split.length; i++) {
String modulePath = StringUtils.join(split, "/", 1, i + 1);
String path = StringUtils.join("/", modulePath);
BaseTreeNode baseTreeNode = modulePathMap.get(path);
if (baseTreeNode == null) {
//创建模块
BaseTreeNode module = new BaseTreeNode();
module.setId(IDGenerator.nextStr());
module.setName(split[i]);
module.setParentId(i == 0 ? ModuleConstants.ROOT_NODE_PARENT_ID : modulePathMap.get(StringUtils.join(split, "/", 0, i)).getId());
if (i != 1) {
String parentId = path.substring(0, path.lastIndexOf("/" + split[i]));
module.setParentId(modulePathMap.get(parentId).getId());
}
module.setPath(path);
addModuleList.add(module);
modulePathMap.put(path, module);
idModuleMap.put(module.getId(), module);
@ -295,10 +307,14 @@ public class ApiDefinitionImportUtilService {
});
Map<String, ApiDefinitionImportDTO> logData = apiDeatlWithDataUpdate.getLogData();
Project project = projectMapper.selectByPrimaryKey(request.getProjectId());
List<ApiDefinitionCaseDTO> updateLists = new ArrayList<>();
if (MapUtils.isNotEmpty(logData)) {
logData.forEach((k, v) -> {
ApiDefinitionDTO apiDefinitionDTO = new ApiDefinitionDTO();
BeanUtils.copyBean(apiDefinitionDTO, v);
ApiDefinitionCaseDTO apiDefinitionCaseDTO = new ApiDefinitionCaseDTO();
BeanUtils.copyBean(apiDefinitionCaseDTO, v);
updateLists.add(apiDefinitionCaseDTO);
LogDTO dto = new LogDTO(
project.getId(),
project.getOrganizationId(),
@ -314,6 +330,7 @@ public class ApiDefinitionImportUtilService {
operationLogs.add(dto);
});
}
List<ApiDefinitionCaseDTO> createLists = new ArrayList<>();
addModuleData.forEach(t -> {
ApiDefinition apiDefinition = new ApiDefinition();
BeanUtils.copyBean(apiDefinition, t);
@ -352,11 +369,22 @@ public class ApiDefinitionImportUtilService {
dto.setPath("/api/definition/import");
dto.setMethod(HttpMethodConstants.POST.name());
dto.setOriginalValue(JSON.toJSONBytes(apiDefinitionDTO));
ApiDefinitionCaseDTO apiDefinitionCaseDTO = new ApiDefinitionCaseDTO();
BeanUtils.copyBean(apiDefinitionCaseDTO, t);
createLists.add(apiDefinitionCaseDTO);
});
sqlSession.flushStatements();
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
operationLogService.batchAdd(operationLogs);
//发送通知
List<Map> createResources = new ArrayList<>();
createResources.addAll(JSON.parseArray(JSON.toJSONString(createLists), Map.class));
afterReturningNoticeSendService.sendNotice(NoticeConstants.TaskType.API_DEFINITION_TASK, NoticeConstants.Event.CREATE, createResources, user, request.getProjectId());
List<Map> updateResources = new ArrayList<>();
updateResources.addAll(JSON.parseArray(JSON.toJSONString(updateResources), Map.class));
afterReturningNoticeSendService.sendNotice(NoticeConstants.TaskType.API_DEFINITION_TASK, NoticeConstants.Event.UPDATE, updateResources, user, request.getProjectId());
}
private void getNeedUpdateData(ImportRequest request, ApiDeatlWithData apiDeatlWithData, ApiDeatlWithDataUpdate apiDeatlWithDataUpdate) {
@ -367,6 +395,7 @@ public class ApiDefinitionImportUtilService {
List<ApiDefinitionImportDTO> updateModuleData = new ArrayList<>();
List<ApiDefinitionImportDTO> updateRequestData = new ArrayList<>();
List<ApiDefinitionImportDTO> addData = new ArrayList<>();
Map<String, ApiDefinitionImportDTO> logMap = new HashMap<>();
//判断参数是否一样 一样的参数需要判断是否需要覆盖模块 如果需要就要update数据 如果不需要 就直接跳过
if (CollectionUtils.isNotEmpty(sameList) && getFullCoverage(request.getCoverData())) {
//需要覆盖数据的 会判断是否需要覆盖模块
@ -376,7 +405,6 @@ public class ApiDefinitionImportUtilService {
ApiDefinitionBlobExample blobExample = new ApiDefinitionBlobExample();
blobExample.createCriteria().andIdIn(sameIds);
List<ApiDefinitionBlob> apiDefinitionBlobs = apiDefinitionBlobMapper.selectByExampleWithBLOBs(blobExample);
Map<String, ApiDefinitionImportDTO> logMap = new HashMap<>();
Map<String, ApiDefinitionBlob> blobMap = apiDefinitionBlobs.stream().collect(Collectors.toMap(ApiDefinitionBlob::getId, t -> t));
//判断参数是否一样
for (ApiDefinitionImportDTO apiDefinitionDTO : sameData) {
@ -412,6 +440,7 @@ public class ApiDefinitionImportUtilService {
apiDeatlWithDataUpdate.setUpdateModuleData(updateModuleData);
apiDeatlWithDataUpdate.setUpdateRequestData(updateRequestData);
apiDeatlWithDataUpdate.setAddModuleData(addData);
apiDeatlWithDataUpdate.setLogData(logMap);
}
private void checkApiDataOnly(ImportRequest request,
@ -453,7 +482,7 @@ public class ApiDefinitionImportUtilService {
if (CollectionUtils.isNotEmpty(dbHeaders) || CollectionUtils.isNotEmpty(importHeaders)) {
List<String> dbHeaderKeys = dbHeaders.stream().map(Header::getKey).toList();
List<String> importHeaderKeys = importHeaders.stream().map(Header::getKey).toList();
if (!paramsIsSame(dbHeaderKeys, importHeaderKeys)) {
if (paramsIsSame(dbHeaderKeys, importHeaderKeys)) {
return false;
}
}
@ -463,7 +492,7 @@ public class ApiDefinitionImportUtilService {
if (CollectionUtils.isNotEmpty(dbQuery) || CollectionUtils.isNotEmpty(importQuery)) {
List<String> dbQueryKeys = dbQuery.stream().map(QueryParam::getKey).toList();
List<String> importQueryKeys = importQuery.stream().map(QueryParam::getKey).toList();
if (!paramsIsSame(dbQueryKeys, importQueryKeys)) {
if (paramsIsSame(dbQueryKeys, importQueryKeys)) {
return false;
}
}
@ -472,7 +501,7 @@ public class ApiDefinitionImportUtilService {
if (CollectionUtils.isNotEmpty(dbRest) || CollectionUtils.isNotEmpty(importRest)) {
List<String> dbRestKeys = dbRest.stream().map(RestParam::getKey).toList();
List<String> importRestKeys = importRest.stream().map(RestParam::getKey).toList();
if (!paramsIsSame(dbRestKeys, importRestKeys)) {
if (paramsIsSame(dbRestKeys, importRestKeys)) {
return false;
}
}
@ -493,7 +522,7 @@ public class ApiDefinitionImportUtilService {
if (CollectionUtils.isNotEmpty(fromValues) || CollectionUtils.isNotEmpty(importFromValues)) {
List<String> dbFormKeys = fromValues.stream().map(FormDataKV::getKey).toList();
List<String> importFormKeys = importFromValues.stream().map(FormDataKV::getKey).toList();
if (!paramsIsSame(dbFormKeys, importFormKeys)) {
if (paramsIsSame(dbFormKeys, importFormKeys)) {
return false;
}
}
@ -507,7 +536,7 @@ public class ApiDefinitionImportUtilService {
if (CollectionUtils.isNotEmpty(wwwValues) || CollectionUtils.isNotEmpty(importWwwValues)) {
List<String> dbWwwKeys = wwwValues.stream().map(FormDataKV::getKey).toList();
List<String> importWwwKeys = importWwwValues.stream().map(FormDataKV::getKey).toList();
if (!paramsIsSame(dbWwwKeys, importWwwKeys)) {
if (paramsIsSame(dbWwwKeys, importWwwKeys)) {
return false;
}
}
@ -542,6 +571,14 @@ public class ApiDefinitionImportUtilService {
}
//判断jsonschema的参数是否一样
/**
* 判断jsonschema的参数是否一样
*
* @param jsonSchema 数据库中的数据
* @param importJsonSchema 导入的生成的jsonschema
* @return true 一样 false 不一样 一样的话就不需要更新
*/
private static boolean jsonSchemaIsSame(JsonSchemaItem jsonSchema, JsonSchemaItem importJsonSchema) {
boolean same = true;
if (jsonSchema == null && importJsonSchema == null) {
@ -557,7 +594,7 @@ public class ApiDefinitionImportUtilService {
if (MapUtils.isNotEmpty(properties) || MapUtils.isNotEmpty(importProperties)) {
List<String> dbJsonKeys = properties.keySet().stream().toList();
List<String> importJsonKeys = importProperties.keySet().stream().toList();
if (!paramsIsSame(dbJsonKeys, importJsonKeys)) {
if (paramsIsSame(dbJsonKeys, importJsonKeys)) {
return false;
}
//遍历判断每个参数是否一样
@ -585,11 +622,11 @@ public class ApiDefinitionImportUtilService {
private static boolean paramsIsSame(List<String> dbRestKeys, List<String> importRestKeys) {
if (dbRestKeys.size() != importRestKeys.size()) {
return false;
return true;
}
//看看是否有差集
List<String> differenceRest = dbRestKeys.stream().filter(t -> !importRestKeys.contains(t)).toList();
return CollectionUtils.isEmpty(differenceRest);
return !CollectionUtils.isEmpty(differenceRest);
}
private Boolean getFullCoverage(Boolean fullCoverage) {
@ -602,24 +639,23 @@ public class ApiDefinitionImportUtilService {
/**
* 构造树结构 但是这里需要module的path
*
* @param projectId
* @param protocol
* @return
* @param projectId 项目id
* @param protocol 协议
* @return 树结构
*/
public List<BaseTreeNode> buildTreeData(String projectId, String protocol) {
ApiModuleRequest request = new ApiModuleRequest();
request.setProjectId(projectId);
request.setProtocol(protocol);
List<BaseTreeNode> fileModuleList = extApiDefinitionModuleMapper.selectBaseByRequest(request);
return this.buildTreeAndCountResource(fileModuleList, true, Translator.get(UNPLANNED_API));
List<BaseTreeNode> apiModuleList = extApiDefinitionModuleMapper.selectBaseByRequest(request);
return this.buildTreeAndCountResource(apiModuleList, true, Translator.get(UNPLANNED_API));
}
public List<BaseTreeNode> buildTreeAndCountResource(List<BaseTreeNode> traverseList, boolean haveVirtualRootNode, String virtualRootName) {
List<BaseTreeNode> baseTreeNodeList = new ArrayList<>();
if (haveVirtualRootNode) {
BaseTreeNode defaultNode = new BaseTreeNode(ModuleConstants.DEFAULT_NODE_ID, virtualRootName, ModuleConstants.NODE_TYPE_DEFAULT, ModuleConstants.ROOT_NODE_PARENT_ID);
defaultNode.setAttachInfo(Map.of(MODULE, StringUtils.join("/", defaultNode.getName())));
defaultNode.setPath(StringUtils.join("/", defaultNode.getName()));
baseTreeNodeList.add(defaultNode);
}
int lastSize = 0;
@ -630,13 +666,13 @@ public class ApiDefinitionImportUtilService {
for (BaseTreeNode treeNode : traverseList) {
if (StringUtils.equalsIgnoreCase(treeNode.getParentId(), ModuleConstants.ROOT_NODE_PARENT_ID)) {
BaseTreeNode node = new BaseTreeNode(treeNode.getId(), treeNode.getName(), treeNode.getType(), treeNode.getParentId());
node.setAttachInfo(Map.of(MODULE, StringUtils.join("/", node.getName())));
node.setPath(StringUtils.join("/", node.getName()));
baseTreeNodeList.add(node);
baseTreeNodeMap.put(treeNode.getId(), node);
} else {
if (baseTreeNodeMap.containsKey(treeNode.getParentId())) {
BaseTreeNode node = new BaseTreeNode(treeNode.getId(), treeNode.getName(), treeNode.getType(), treeNode.getParentId());
node.setAttachInfo(Map.of(MODULE, StringUtils.join(baseTreeNodeMap.get(treeNode.getParentId()).getAttachInfo().get(MODULE), "/", node.getName())));
node.setPath(StringUtils.join(baseTreeNodeMap.get(treeNode.getParentId()).getPath(), "/", node.getName()));
baseTreeNodeList.add(node);
}
}
@ -646,5 +682,4 @@ public class ApiDefinitionImportUtilService {
return baseTreeNodeList;
}
}

View File

@ -126,15 +126,6 @@ public class ApiDefinitionModuleService extends ModuleTreeService {
example.clear();
}
private String getRootNodeId(ApiDefinitionModule module) {
if (StringUtils.equals(module.getParentId(), ModuleConstants.ROOT_NODE_PARENT_ID)) {
return module.getId();
} else {
ApiDefinitionModule parentModule = apiDefinitionModuleMapper.selectByPrimaryKey(module.getParentId());
return this.getRootNodeId(parentModule);
}
}
public void update(ModuleUpdateRequest request, String userId) {
ApiDefinitionModule module = checkModuleExist(request.getId());
ApiDefinitionModule updateModule = new ApiDefinitionModule();
@ -270,20 +261,36 @@ public class ApiDefinitionModuleService extends ModuleTreeService {
return moduleCountMap;
}
public List<BaseTreeNode> getTrashTree(ApiModuleRequest request, boolean deleted) {
public List<BaseTreeNode> getTrashTree(ApiModuleRequest request) {
ApiDefinitionExample example = new ApiDefinitionExample();
example.createCriteria().andProjectIdEqualTo(request.getProjectId()).andDeletedEqualTo(true).andProtocolEqualTo(request.getProtocol());
example.createCriteria()
.andProjectIdEqualTo(request.getProjectId())
.andDeletedEqualTo(true)
.andProtocolEqualTo(request.getProtocol());
List<ApiDefinition> apiDefinitions = apiDefinitionMapper.selectByExample(example);
if (CollectionUtils.isEmpty(apiDefinitions)) {
return new ArrayList<>();
}
List<String> moduleIds = apiDefinitions.stream().map(ApiDefinition::getModuleId).distinct().toList();
List<BaseTreeNode> baseTreeNodes = extApiDefinitionModuleMapper.selectBaseByIds(moduleIds);
super.buildTreeAndCountResource(baseTreeNodes, true, Translator.get(UNPLANNED_API));
List<ApiTreeNode> apiTreeNodeList = extApiDefinitionModuleMapper.selectApiDataByRequest(request, deleted);
return apiDebugModuleService.getBaseTreeNodes(apiTreeNodeList, baseTreeNodes);
List<BaseTreeNode> baseTreeNodes = getNodeByNodeIds(moduleIds);
return super.buildTreeAndCountResource(baseTreeNodes, true, Translator.get(UNPLANNED_API));
}
public List<BaseTreeNode> getNodeByNodeIds(List<String> moduleIds) {
List<String> finalModuleIds = new ArrayList<>(moduleIds);
List<BaseTreeNode> totalList = new ArrayList<>();
while (CollectionUtils.isNotEmpty(finalModuleIds)) {
List<BaseTreeNode> modules = extApiDefinitionModuleMapper.selectBaseByIds(finalModuleIds);
totalList.addAll(modules);
List<String> finalModuleIdList = finalModuleIds;
List<String> parentModuleIds = modules.stream().map(BaseTreeNode::getParentId).filter(parentId -> !StringUtils.equalsIgnoreCase(parentId, ModuleConstants.ROOT_NODE_PARENT_ID) && !finalModuleIdList.contains(parentId)).toList();
finalModuleIds.clear();
finalModuleIds = new ArrayList<>(parentModuleIds);
}
return totalList.stream().distinct().toList();
}
public EnvApiTreeDTO envTree(EnvApiModuleRequest request) {
EnvApiTreeDTO envApiTreeDTO = new EnvApiTreeDTO();
ApiModuleRequest apiModuleRequest = new ApiModuleRequest();

View File

@ -7,7 +7,6 @@ import io.metersphere.api.domain.*;
import io.metersphere.api.dto.debug.ApiFileResourceUpdateRequest;
import io.metersphere.api.dto.definition.*;
import io.metersphere.api.dto.definition.importdto.ApiDefinitionImport;
import io.metersphere.api.dto.definition.importdto.ApiDefinitionImportDTO;
import io.metersphere.api.dto.request.ImportRequest;
import io.metersphere.api.mapper.*;
import io.metersphere.api.parser.ImportParser;
@ -28,7 +27,7 @@ import io.metersphere.sdk.util.*;
import io.metersphere.system.dto.OperationHistoryDTO;
import io.metersphere.system.dto.request.OperationHistoryRequest;
import io.metersphere.system.dto.request.OperationHistoryVersionRequest;
import io.metersphere.system.dto.sdk.OptionDTO;
import io.metersphere.system.dto.sdk.SessionUser;
import io.metersphere.system.dto.table.TableBatchProcessDTO;
import io.metersphere.system.log.constants.OperationLogModule;
import io.metersphere.system.service.OperationHistoryService;
@ -63,6 +62,7 @@ public class ApiDefinitionService {
private static final String ALL_API = "api_definition_module.api.all";
private static final String UNPLANNED_API = "api_unplanned_request";
private static final String API_TABLE = "api_definition";
@Resource
private ApiDefinitionMapper apiDefinitionMapper;
@ -886,7 +886,7 @@ public class ApiDefinitionService {
return apiDefinitionDocDTO;
}
public ApiDefinitionImport apiTestImport(MultipartFile file, ImportRequest request, String userId, String projectId) {
public ApiDefinitionImport apiTestImport(MultipartFile file, ImportRequest request, SessionUser user, String projectId) {
if (file != null) {
String originalFilename = file.getOriginalFilename();
if (StringUtils.isNotBlank(originalFilename)) {
@ -894,38 +894,25 @@ public class ApiDefinitionService {
apiDefinitionImportUtilService.checkFileSuffixName(request, suffixName);
}
}
request.setUserId(userId);
if (StringUtils.isBlank(request.getProjectId())) {
request.setProjectId(projectId);
}
ImportParser<?> runService = ImportParserFactory.getImportParser(request.getPlatform());
ApiDefinitionImport apiImport = null;
if (StringUtils.equals(request.getType(), "SCHEDULE")) {
request.setProtocol("HTTP");
request.setProtocol(ModuleConstants.NODE_PROTOCOL_HTTP);
}
try {
apiImport = (ApiDefinitionImport) Objects.requireNonNull(runService).parse(file == null ? null : file.getInputStream(), request);
//TODO 处理mock数据
// 发送通知
} catch (Exception e) {
// TODO 发送通知
LogUtils.error(e.getMessage(), e);
throw new MSException(Translator.get("parse_data_error"));
}
try {
apiDefinitionImportUtilService.importApi(request, apiImport);
apiDefinitionMapper.selectByExample(new ApiDefinitionExample());
if (CollectionUtils.isNotEmpty(apiImport.getData())) {
List<String> names = apiImport.getData().stream().map(ApiDefinitionImportDTO::getName).collect(Collectors.toList());
request.setName(String.join(",", names));
List<String> ids = apiImport.getData().stream().map(ApiDefinitionImportDTO::getId).collect(Collectors.toList());
request.setId(JSON.toJSONString(ids));
}
// 发送通知
//apiDefinitionImportUtilService.sendImportNotice(request, apiImportSendNoticeDTOS, project);
apiDefinitionImportUtilService.importApi(request, apiImport, user);
} catch (Exception e) {
//apiDefinitionImportUtilService.sendFailMessage(request, project);
LogUtils.error(e);
throw new MSException(Translator.get("user_import_format_wrong"));
}
@ -933,18 +920,11 @@ public class ApiDefinitionService {
}
public List<OperationHistoryDTO> list(OperationHistoryRequest request) {
List<OperationHistoryDTO> operationHistoryList = operationHistoryService.list(request);
if (CollectionUtils.isNotEmpty(operationHistoryList)) {
List<String> apiIds = operationHistoryList.stream()
.map(OperationHistoryDTO::getSourceId).toList();
Map<String, String> apiMap = extApiDefinitionMapper.selectVersionOptionByIds(apiIds).stream()
.collect(Collectors.toMap(OptionDTO::getId, OptionDTO::getName));
operationHistoryList.forEach(item -> item.setVersionName(apiMap.getOrDefault(item.getSourceId(), StringUtils.EMPTY)));
XpackApiDefinitionService xpackApiDefinitionService = CommonBeanFactory.getBean(XpackApiDefinitionService.class);
if (xpackApiDefinitionService != null) {
return xpackApiDefinitionService.listHis(request, API_TABLE);
}
return operationHistoryList;
return new ArrayList<>();
}
/**

View File

@ -17,13 +17,9 @@ import io.metersphere.sdk.domain.Environment;
import io.metersphere.sdk.domain.EnvironmentExample;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.mapper.EnvironmentMapper;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.FileAssociationSourceUtil;
import io.metersphere.sdk.util.SubListUtils;
import io.metersphere.sdk.util.Translator;
import io.metersphere.sdk.util.*;
import io.metersphere.system.dto.OperationHistoryDTO;
import io.metersphere.system.dto.request.OperationHistoryRequest;
import io.metersphere.system.dto.sdk.OptionDTO;
import io.metersphere.system.dto.sdk.request.PosRequest;
import io.metersphere.system.log.constants.OperationLogModule;
import io.metersphere.system.service.OperationHistoryService;
@ -85,6 +81,7 @@ public class ApiTestCaseService {
private ApiDefinitionModuleMapper apiDefinitionModuleMapper;
@Resource
private OperationHistoryService operationHistoryService;
private static final String CASE_TABLE = "api_test_case";
private void checkProjectExist(String projectId) {
Project project = projectMapper.selectByPrimaryKey(projectId);
@ -371,10 +368,13 @@ public class ApiTestCaseService {
public List<String> doSelectIds(ApiTestCaseBatchRequest request, boolean deleted) {
if (request.isSelectAll()) {
List<String> ids = extApiTestCaseMapper.getIds(request, deleted);
if (CollectionUtils.isNotEmpty(request.getExcludeIds())) {
if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(request.getSelectIds())) {
ids.addAll(request.getSelectIds());
}
if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(request.getExcludeIds())) {
ids.removeAll(request.getExcludeIds());
}
return ids;
return new ArrayList<>(ids.stream().distinct().toList());
} else {
request.getSelectIds().removeAll(request.getExcludeIds());
return request.getSelectIds();
@ -560,19 +560,13 @@ public class ApiTestCaseService {
return executeList;
}
public List<OperationHistoryDTO> getHistoryList(OperationHistoryRequest request) {
List<OperationHistoryDTO> operationHistoryList = operationHistoryService.list(request);
if (CollectionUtils.isNotEmpty(operationHistoryList)) {
List<String> apiIds = operationHistoryList.stream()
.map(OperationHistoryDTO::getSourceId).toList();
Map<String, String> apiMap = extApiTestCaseMapper.selectVersionOptionByIds(apiIds).stream()
.collect(Collectors.toMap(OptionDTO::getId, OptionDTO::getName));
operationHistoryList.forEach(item -> item.setVersionName(apiMap.getOrDefault(item.getSourceId(), StringUtils.EMPTY)));
public List<OperationHistoryDTO> operationHistoryList(OperationHistoryRequest request) {
XpackApiDefinitionService xpackApiDefinitionService = CommonBeanFactory.getBean(XpackApiDefinitionService.class);
if (xpackApiDefinitionService != null) {
return xpackApiDefinitionService.listHis(request, CASE_TABLE);
}
return operationHistoryList;
return new ArrayList<>();
}
public void updatePriority(String id, String priority, String userId) {

View File

@ -0,0 +1,20 @@
package io.metersphere.api.service.definition;
import io.metersphere.system.dto.OperationHistoryDTO;
import io.metersphere.system.dto.request.OperationHistoryRequest;
import java.util.List;
/**
* 接口管理Xpack功能接口
*/
public interface XpackApiDefinitionService {
/**
* 功能用例变更历史分页列表
*
* @param request 请求参数
* @return 变更历史集合
*/
List<OperationHistoryDTO> listHis(OperationHistoryRequest request, String table);
}

View File

@ -260,7 +260,21 @@ public class ApiScenarioModuleService extends ModuleTreeService {
return new ArrayList<>();
}
List<String> moduleIds = apiScenarios.stream().map(ApiScenario::getModuleId).distinct().toList();
List<BaseTreeNode> baseTreeNodes = extApiScenarioModuleMapper.selectBaseByIds(moduleIds);
List<BaseTreeNode> baseTreeNodes = getNodeByNodeIds(moduleIds);
return super.buildTreeAndCountResource(baseTreeNodes, true, Translator.get(UNPLANNED_SCENARIO));
}
public List<BaseTreeNode> getNodeByNodeIds(List<String> moduleIds) {
List<String> finalModuleIds = new ArrayList<>(moduleIds);
List<BaseTreeNode> totalList = new ArrayList<>();
while (CollectionUtils.isNotEmpty(finalModuleIds)) {
List<BaseTreeNode> modules = extApiScenarioModuleMapper.selectBaseByIds(finalModuleIds);
totalList.addAll(modules);
List<String> finalModuleIdList = finalModuleIds;
List<String> parentModuleIds = modules.stream().map(BaseTreeNode::getParentId).filter(parentId -> !StringUtils.equalsIgnoreCase(parentId, ModuleConstants.ROOT_NODE_PARENT_ID) && !finalModuleIdList.contains(parentId)).toList();
finalModuleIds.clear();
finalModuleIds = new ArrayList<>(parentModuleIds);
}
return totalList.stream().distinct().toList();
}
}

View File

@ -8,7 +8,11 @@ import io.metersphere.api.service.definition.ApiDefinitionScheduleService;
import io.metersphere.api.service.definition.ApiDefinitionService;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.CommonBeanFactory;
import io.metersphere.system.dto.sdk.SessionUser;
import io.metersphere.system.dto.user.UserDTO;
import io.metersphere.system.schedule.BaseScheduleJob;
import io.metersphere.system.service.UserService;
import io.metersphere.system.utils.SessionUtils;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
@ -17,10 +21,12 @@ import org.quartz.TriggerKey;
public class SwaggerUrlImportJob extends BaseScheduleJob {
private ApiDefinitionService apiDefinitionService;
private ApiDefinitionScheduleService apiDefinitionScheduleService;
private UserService userService;
public SwaggerUrlImportJob() {
apiDefinitionService = CommonBeanFactory.getBean(ApiDefinitionService.class);
apiDefinitionScheduleService = CommonBeanFactory.getBean(ApiDefinitionScheduleService.class);
userService = CommonBeanFactory.getBean(UserService.class);
}
@Override
@ -34,7 +40,10 @@ public class SwaggerUrlImportJob extends BaseScheduleJob {
request.setUserId(jobDataMap.getString("userId"));
request.setType("SCHEDULE");
request.setResourceId(resourceId);
apiDefinitionService.apiTestImport(null, request, request.getUserId(), request.getProjectId());
UserDTO userDTO = userService.getUserDTOByKeyword(request.getUserId());
SessionUser user = SessionUser.fromUser(userDTO, SessionUtils.getSessionId());
apiDefinitionService.apiTestImport(null, request, user, request.getProjectId());
}
public static JobKey getJobKey(String resourceId) {

View File

@ -269,6 +269,30 @@ public class ApiDefinitionModuleControllerTests extends BaseTest {
initApiDebugData(a1ChildNode.getId());
checkLog(a1ChildNode.getId(), OperationLogType.ADD, URL_MODULE_ADD);
//继续创建a2下继续创建a2-a1
request = new ModuleCreateRequest();
request.setProjectId(project.getId());
request.setName("a2-a1");
request.setParentId(a2Node.getId());
this.requestPostWithOkAndReturn(URL_MODULE_ADD, request);
treeNodes = this.getModuleTreeNode();
BaseTreeNode a2ChildNode = null;
for (BaseTreeNode baseTreeNode : treeNodes) {
Assertions.assertNotNull(baseTreeNode.getParentId());
if (StringUtils.equals(baseTreeNode.getName(), "a2") && CollectionUtils.isNotEmpty(baseTreeNode.getChildren())) {
for (BaseTreeNode childNode : baseTreeNode.getChildren()) {
Assertions.assertNotNull(childNode.getParentId());
if (StringUtils.equals(childNode.getName(), "a2-a1") && StringUtils.equals(childNode.getType(), ModuleConstants.NODE_TYPE_DEFAULT)) {
a2ChildNode = childNode;
}
}
}
}
Assertions.assertNotNull(a2ChildNode);
initApiDebugData(a2ChildNode.getId());
checkLog(a2ChildNode.getId(), OperationLogType.ADD, URL_MODULE_ADD);
//a1的子节点a1下继续创建节点a1-a1-c1
request = new ModuleCreateRequest();
request.setProjectId(project.getId());
@ -812,7 +836,6 @@ public class ApiDefinitionModuleControllerTests extends BaseTest {
@Order(10)
public void deleteModuleTestSuccess() throws Exception {
this.preliminaryData();
this.getModuleTrashTreeNode();
// 删除没有文件的节点a1-b1-c1 检查是否级联删除根节点
BaseTreeNode a1b1Node = getNodeByName(this.getModuleTreeNode(), "a1-b1");
@ -843,10 +866,19 @@ public class ApiDefinitionModuleControllerTests extends BaseTest {
@Test
@Order(11)
public void getModuleTrashTreeNode() throws Exception {
BaseTreeNode a2a1Node = getNodeByName(this.getModuleTreeNode(), "a2-a1");
//将模块为a2-a1的节点数据放入回收站
ApiDefinitionExample example = new ApiDefinitionExample();
assert a2a1Node != null;
example.createCriteria().andModuleIdEqualTo(a2a1Node.getId());
ApiDefinition apiDefinition = new ApiDefinition();
apiDefinition.setDeleted(true);
apiDefinitionMapper.updateByExampleSelective(apiDefinition, example);
MvcResult result = this.requestPostWithOkAndReturn(URL_MODULE_TRASH_TREE, new ApiModuleRequest() {{
this.setProtocol("HTTP");
this.setProjectId(project.getId());
}});
String returnData = result.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class);
JSON.parseArray(JSON.toJSONString(resultHolder.getData()), BaseTreeNode.class);

View File

@ -31,6 +31,7 @@ import io.metersphere.system.dto.OperationHistoryDTO;
import io.metersphere.system.dto.request.OperationHistoryRequest;
import io.metersphere.system.dto.sdk.request.PosRequest;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.service.OperationHistoryService;
import io.metersphere.system.uid.IDGenerator;
import io.metersphere.system.uid.NumGenerator;
import io.metersphere.system.utils.Pager;
@ -115,6 +116,8 @@ public class ApiTestCaseControllerTests extends BaseTest {
private ApiReportService apiReportService;
@Resource
private ProjectVersionMapper projectVersionMapper;
@Resource
private OperationHistoryService operationHistoryService;
public static <T> T parseObjectFromMvcResult(MvcResult mvcResult, Class<T> parseClass) {
try {
@ -839,6 +842,16 @@ public class ApiTestCaseControllerTests extends BaseTest {
Assertions.assertNotNull(returnPager);
List<OperationHistoryDTO> reportDTOS = JSON.parseArray(JSON.toJSONString(returnPager.getList()), OperationHistoryDTO.class);
reportDTOS.forEach(reportDTO -> Assertions.assertEquals(reportDTO.getSourceId(), first.getId()));
List<OperationHistoryDTO> operationHistoryDTOS = operationHistoryService.listWidthLimit(request, "api_test_case");
Assertions.assertTrue(org.apache.commons.collections4.CollectionUtils.isNotEmpty(operationHistoryDTOS));
request = new OperationHistoryRequest();
request.setProjectId(DEFAULT_PROJECT_ID);
request.setSourceId("111");
request.setPageSize(10);
request.setCurrent(1);
responsePost(HISTORY, request);
}
@Test