feat(接口测试): 接口管理模块回收站数据恢复/删除功能

This commit is contained in:
lan-yonghui 2023-11-23 20:11:50 +08:00 committed by Craftsman
parent 674927efab
commit f34d056dd1
15 changed files with 945 additions and 204 deletions

View File

@ -48,6 +48,12 @@ public class DefaultRepositoryDir {
private static final String PROJECT_API_DEBUG_DIR = PROJECT_DIR + "/api-debug/%s";
private static final String PROJECT_BUG_DIR = PROJECT_DIR + "/bug/%s";
/**
* 接口定义相关文件的存储目录
* project/{projectId}/api-definition/{apiId}
*/
private static final String PROJECT_API_DEFINITION_DIR = PROJECT_DIR + "/api-definition/%s";
/*------ end: 项目下资源目录 --------*/
@ -82,4 +88,8 @@ public class DefaultRepositoryDir {
public static String getApiDebugDir(String projectId, String apiDebugId) {
return String.format(PROJECT_API_DEBUG_DIR, projectId, apiDebugId);
}
public static String getApiDefinitionDir(String projectId, String apiId) {
return String.format(PROJECT_API_DEFINITION_DIR, projectId, apiId);
}
}

View File

@ -116,12 +116,41 @@ public class ApiDefinitionController {
}
@PostMapping("/page")
@Operation(summary = "接口测试-接口管理-接口列表")
@Operation(summary = "接口测试-接口管理-接口列表(deleted 状态为 0 时为回收站数据)")
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_READ)
public Pager<List<ApiDefinitionDTO>> getPage(@Validated @RequestBody ApiDefinitionPageRequest request) {
Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize(),
StringUtils.isNotBlank(request.getSortString()) ? request.getSortString() : "create_time desc");
return PageUtils.setPageInfo(page, apiDefinitionService.getApiDefinitionPage(request, false));
return PageUtils.setPageInfo(page, apiDefinitionService.getApiDefinitionPage(request));
}
@PostMapping(value = "/restore")
@Operation(summary = "接口测试-接口管理-恢复回收站接口定义")
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_UPDATE)
@Log(type = OperationLogType.UPDATE, expression = "#msClass.restoreLog(#request)", msClass = ApiDefinitionLogService.class)
public void restore(@Validated @RequestBody ApiDefinitionDeleteRequest request) {
apiDefinitionService.restore(request, SessionUtils.getUserId());
}
@PostMapping(value = "/recycle-del")
@Operation(summary = "接口测试-接口管理-删除回收站接口定义")
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_DELETE)
@Log(type = OperationLogType.DELETE, expression = "#msClass.recycleDelLog(#request)", msClass = ApiDefinitionLogService.class)
public void recycleDel(@Validated @RequestBody ApiDefinitionDeleteRequest request) {
apiDefinitionService.recycleDel(request, SessionUtils.getUserId());
}
@PostMapping(value = "/batch-restore")
@Operation(summary = "接口测试-接口管理-批量从回收站恢复接口定义")
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_UPDATE)
@Log(type = OperationLogType.UPDATE, expression = "#msClass.batchRestoreLog(#request)", msClass = ApiDefinitionLogService.class)
public void batchRestore(@Validated @RequestBody ApiDefinitionBatchRequest request) {
apiDefinitionService.batchRestore(request, SessionUtils.getUserId());
}
@PostMapping(value = "/batch-recycle-del")
@Operation(summary = "接口测试-接口管理-批量从回收站删除接口定义")
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_DELETE)
public void batchRecycleDel(@Validated @RequestBody ApiDefinitionBatchRequest request) {
apiDefinitionService.batchRecycleDel(request, SessionUtils.getUserId());
}
}

View File

@ -9,6 +9,7 @@ import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.LinkedHashSet;
import java.util.List;
/**
* @author lan
@ -63,4 +64,17 @@ public class ApiDefinitionAddRequest implements Serializable {
@Schema(description = "请求内容")
@NotBlank
private String request;
@Schema(description = "请求内容")
@NotBlank
private String response;
/**
* 文件ID列表
* 需要和上传的文件顺序保持一致
* 为了解决文件名称重复的问题需要把文件和ID一一对应
* 创建时先按ID创建目录再把文件放入目录
*/
@Schema(description = "接口所需的所有文件资源ID与上传的文件顺序保持一致")
private List<String> fileIds;
}

View File

@ -5,21 +5,21 @@ import io.metersphere.plugin.api.spi.AbstractMsTestElement;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.util.List;
/**
* @author lan
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class ApiDefinitionDTO extends ApiDefinition{
@Schema(description = "请求内容")
private AbstractMsTestElement request;
@Schema(description = "响应内容")
private String response;
private List<HttpResponse> response;
@Schema(description = "创建人名称")
private String createUserName;

View File

@ -1,5 +1,6 @@
package io.metersphere.api.dto.definition;
import io.metersphere.sdk.constants.ModuleConstants;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
@ -27,8 +28,13 @@ public class ApiDefinitionDeleteRequest implements Serializable {
@Size(min = 1, max = 50, message = "{api_definition.project_id.length_range}")
private String projectId;
@Schema(description = "接口协议", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{api_debug.protocol.not_blank}")
@Size(min = 1, max = 20, message = "{api_debug.protocol.length_range}")
private String protocol = ModuleConstants.NODE_PROTOCOL_HTTP;
@Schema(description = "删除列表版本/删除全部版本")
private Boolean deleteAll;
private Boolean deleteAll = false;
}

View File

@ -45,4 +45,7 @@ public class ApiDefinitionPageRequest extends BasePageRequest {
@Schema(description = "模块ID(根据模块树查询时要把当前节点以及子节点都放在这里。)")
private List<String> moduleIds;
@Schema(description = "删除状态(状态为 0 时为回收站数据)")
private Boolean deleted = false;
}

View File

@ -7,6 +7,7 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
import java.util.List;
/**
* @author lan
@ -23,4 +24,11 @@ public class ApiDefinitionUpdateRequest extends ApiDefinitionAddRequest {
@Size(min = 1, max = 50, message = "{api_definition.id.length_range}")
private String id;
/**
* 新上传的文件ID
* 为了解决文件名称重复的问题需要把文件和ID一一对应
* 创建时先按ID创建目录再把文件放入目录
*/
@Schema(description = "新上传的文件ID与上传的文件顺序保持一致")
private List<String> addFileIds;
}

View File

@ -0,0 +1,51 @@
package io.metersphere.api.dto.definition;
import io.metersphere.sdk.constants.ModuleConstants;
import io.metersphere.sdk.dto.api.request.http.Header;
import io.metersphere.sdk.dto.api.request.http.body.Body;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
/**
* @author: LAN
* @date: 2023/11/21 18:12
* @version: 1.0
*/
@Data
public class HttpResponse {
@Schema(description = "响应编号")
private Integer id;
@Schema(description = "响应类型")
private String type = ModuleConstants.NODE_PROTOCOL_HTTP;
@Schema(description = "响应名称")
private String name;
/**
* 请求头
*/
@Schema(description = "响应请求头")
private List<Header> headers;
/**
* 请求体
*/
@Schema(description = "响应请求体")
private Body body;
/**
* 请求方法
*/
@Schema(description = "响应请求方法")
private String statusCode;
/**
* 默认标识
*/
@Schema(description = "默认响应标识")
private Boolean defaultFlag;
}

View File

@ -10,7 +10,7 @@ import java.util.List;
public interface ExtApiDefinitionMapper {
void deleteApiToGc(@Param("ids") List<String> ids, @Param("userId") String userId, @Param("time") long time);
List<ApiDefinitionDTO> list(@Param("request") ApiDefinitionPageRequest request, @Param("deleted") boolean deleted);
List<ApiDefinitionDTO> list(@Param("request") ApiDefinitionPageRequest request);
List<ApiCaseComputeDTO> selectApiCaseByIdsAndStatusIsNotTrash(@Param("ids") List<String> ids, @Param("projectId") String projectId);
@ -18,15 +18,21 @@ public interface ExtApiDefinitionMapper {
List<String> getIds(@Param("request") TableBatchProcessDTO request, @Param("projectId") String projectId, @Param("protocol") String protocol, @Param("deleted") boolean deleted);
List<String> getRefIds(@Param("ids") List<String> ids);
List<String> getRefIds(@Param("ids") List<String> ids, @Param("deleted") boolean deleted);
List<ApiDefinition> getTagsByIds(@Param("ids") List<String> ids);
List<String> getIdsByRefId(@Param("refIds") List<String> refIds, @Param("deleted") boolean deleted);
List<ApiDefinition> getTagsByIds(@Param("ids") List<String> ids, @Param("deleted") boolean deleted);
List<ApiDefinitionVersionDTO> getApiDefinitionByRefId(@Param("refId") String refId);
void batchMove(@Param("request") ApiDefinitionBatchMoveRequest request, @Param("ids") List<String> ids, @Param("userId") String userId);
void batchDelete(@Param("ids") List<String> ids, @Param("userId") String userId);
void batchDeleteByRefId(@Param("refIds") List<String> refIds, @Param("userId") String userId, @Param("projectId") String projectId);
void batchDeleteById(@Param("ids") List<String> ids, @Param("userId") String userId, @Param("projectId") String projectId);
void batchRestoreById(@Param("ids") List<String> ids, @Param("userId") String userId, @Param("projectId") String projectId);
void clearLatestVersion(@Param("refId") String refId, @Param("projectId") String projectId);

View File

@ -21,7 +21,7 @@
api_definition.deleted, project_version.name as version_name
from api_definition
LEFT JOIN project_version ON project_version.id = api_definition.version_id
where deleted = #{deleted}
where deleted = #{request.deleted}
<include refid="queryWhereCondition"/>
</select>
@ -62,6 +62,12 @@
SELECT id
FROM api_definition
where project_id = #{projectId} AND protocol = #{protocol} and deleted = #{deleted}
<if test="request.moduleIds != null and request.moduleIds.size() != 0">
AND module_id IN
<foreach collection="request.moduleIds" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</if>
<include refid="queryWhereConditionByBaseQueryRequest"/>
</select>
@ -75,9 +81,22 @@
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
and deleted = false
and deleted = #{deleted}
group by ref_id
</select>
<select id="getIdsByRefId" resultType="java.lang.String">
SELECT
id
FROM
api_definition
where ref_id in
<foreach collection="refIds" item="id" open="(" separator="," close=")">
#{id}
</foreach>
and deleted = #{deleted}
</select>
<select id="getApiDefinitionByRefId" resultType="io.metersphere.api.dto.definition.ApiDefinitionVersionDTO">
SELECT id,
`name`,
@ -87,28 +106,56 @@
FROM api_definition
WHERE ref_id = #{refId}
</select>
<select id="getTagsByIds" resultType="io.metersphere.api.domain.ApiDefinition">
select id, tags from api_definition
where id in
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
and deleted = false
and deleted = #{deleted}
</select>
<update id="batchDelete">
<update id="batchDeleteByRefId">
update api_definition
set deleted = 1,
delete_user = #{userId},
delete_time = UNIX_TIMESTAMP()*1000
where ref_id in
<foreach collection="refIds" item="id" open="(" separator="," close=")">
#{id}
</foreach>
and deleted = false and project_id = #{projectId}
</update>
<update id="batchDeleteById">
update api_definition
set deleted = 1,
delete_user = #{userId},
delete_time = UNIX_TIMESTAMP()*1000
where id in
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
and deleted = false
and deleted = false and project_id = #{projectId}
</update>
<update id="batchRestoreById">
update api_definition
set deleted = 0,
delete_user = null,
delete_time = null,
update_user = #{userId},
update_time = UNIX_TIMESTAMP()*1000
where id in
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
and deleted = true and project_id = #{projectId}
</update>
<update id="batchMove">
update api_definition
set module_id = #{request.moduleId},

View File

@ -4,29 +4,33 @@ import io.metersphere.api.domain.ApiDefinition;
import io.metersphere.api.domain.ApiDefinitionExample;
import io.metersphere.api.dto.definition.*;
import io.metersphere.api.mapper.ApiDefinitionMapper;
import io.metersphere.api.mapper.ExtApiDefinitionMapper;
import io.metersphere.project.domain.Project;
import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.sdk.constants.HttpMethodConstants;
import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.dto.table.TableBatchProcessDTO;
import io.metersphere.system.log.constants.OperationLogModule;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.log.dto.LogDTO;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
@Service
@Transactional(rollbackFor = Exception.class)
public class ApiDefinitionLogService {
@Resource
private ApiDefinitionMapper apiDefinitionMapper;
@Resource
private ApiDefinitionService apiDefinitionService;
private ExtApiDefinitionMapper extApiDefinitionMapper;
@Resource
private ProjectMapper projectMapper;
@ -112,7 +116,7 @@ public class ApiDefinitionLogService {
* @return
*/
public List<LogDTO> batchDelLog(ApiDefinitionBatchRequest request) {
List<String> ids = apiDefinitionService.getBatchApiIds(request, request.getProjectId(), request.getProtocol());
List<String> ids = getBatchApiIds(request, request.getProjectId(), request.getProtocol(), false);
List<LogDTO> dtoList = new ArrayList<>();
if (CollectionUtils.isNotEmpty(ids)) {
ApiDefinitionExample example = new ApiDefinitionExample();
@ -144,7 +148,7 @@ public class ApiDefinitionLogService {
* @return
*/
public List<LogDTO> batchUpdateLog(ApiDefinitionBatchUpdateRequest request) {
List<String> ids = apiDefinitionService.getBatchApiIds(request, request.getProjectId(), request.getProtocol());
List<String> ids = getBatchApiIds(request, request.getProjectId(), request.getProtocol(), false);
List<LogDTO> dtoList = new ArrayList<>();
if (CollectionUtils.isNotEmpty(ids)) {
ApiDefinitionExample example = new ApiDefinitionExample();
@ -190,7 +194,7 @@ public class ApiDefinitionLogService {
}
public List<LogDTO> batchMoveLog(ApiDefinitionBatchMoveRequest request) {
List<String> ids = apiDefinitionService.getBatchApiIds(request, request.getProjectId(), request.getProtocol());
List<String> ids = getBatchApiIds(request, request.getProjectId(), request.getProtocol(), false);
List<LogDTO> dtoList = new ArrayList<>();
if (CollectionUtils.isNotEmpty(ids)) {
ApiDefinitionExample example = new ApiDefinitionExample();
@ -235,4 +239,108 @@ public class ApiDefinitionLogService {
}
return null;
}
/**
* 恢复回收站接口定义接口日志
*
* @param request
* @return
*/
public LogDTO restoreLog(ApiDefinitionDeleteRequest request) {
ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey(request.getId());
if(apiDefinition != null){
LogDTO dto = new LogDTO(
request.getProjectId(),
null,
request.getId(),
null,
OperationLogType.UPDATE.name(),
OperationLogModule.API_DEFINITION,
apiDefinition.getName());
dto.setPath("/api/definition/restore");
dto.setMethod(HttpMethodConstants.POST.name());
dto.setOriginalValue(JSON.toJSONBytes(apiDefinition));
return dto;
}
return null;
}
/**
* 批量恢复回收站接口定义接口日志
*
* @return
*/
public List<LogDTO> batchRestoreLog(ApiDefinitionBatchRequest request) {
List<String> ids = getBatchApiIds(request, request.getProjectId(), request.getProtocol(), false);
List<LogDTO> dtoList = new ArrayList<>();
if (CollectionUtils.isNotEmpty(ids)) {
ApiDefinitionExample example = new ApiDefinitionExample();
example.createCriteria().andIdIn(ids).andDeletedEqualTo(false);
List<ApiDefinition> apiDefinitions = apiDefinitionMapper.selectByExample(example);
apiDefinitions.forEach(item -> {
LogDTO dto = new LogDTO(
item.getProjectId(),
"",
item.getId(),
item.getCreateUser(),
OperationLogType.UPDATE.name(),
OperationLogModule.API_DEFINITION,
item.getName());
dto.setPath("/api/definition/batch-restore");
dto.setMethod(HttpMethodConstants.POST.name());
dto.setOriginalValue(JSON.toJSONBytes(item));
dtoList.add(dto);
});
}
return dtoList;
}
/**
* 删除回收站接口定义接口日志
*
* @return
*/
public List<LogDTO> recycleDelLog(List<ApiDefinition> apiDefinitions, String operator, Boolean isBatch) {
List<LogDTO> dtoList = new ArrayList<>();
if (CollectionUtils.isNotEmpty(apiDefinitions)) {
apiDefinitions.forEach(item -> {
LogDTO dto = new LogDTO(
item.getProjectId(),
"",
item.getId(),
operator,
OperationLogType.DELETE.name(),
OperationLogModule.API_DEFINITION,
item.getName());
String path = isBatch ? "/api/definition/batch-recycle-del" : "/api/definition/recycle-del";
dto.setPath(path);
dto.setMethod(HttpMethodConstants.POST.name());
dto.setOriginalValue(JSON.toJSONBytes(item));
dtoList.add(dto);
});
}
return dtoList;
}
// 获取批量操作选中的ID
public <T> List<String> getBatchApiIds(T dto, String projectId, String protocol, boolean deleted) {
TableBatchProcessDTO request = (TableBatchProcessDTO) dto;
if (request.isSelectAll()) {
List<String> ids = extApiDefinitionMapper.getIds(request, projectId, protocol, deleted);
if (CollectionUtils.isNotEmpty(request.getExcludeIds())) {
ids.removeAll(request.getExcludeIds());
}
return ids;
} else {
return request.getSelectIds();
}
}
}

View File

@ -1,27 +1,24 @@
package io.metersphere.api.service.definition;
import io.metersphere.api.constants.ApiResourceType;
import io.metersphere.api.controller.result.ApiResultCode;
import io.metersphere.api.domain.*;
import io.metersphere.api.dto.debug.ApiFileResourceUpdateRequest;
import io.metersphere.api.dto.definition.*;
import io.metersphere.api.enums.ApiReportStatus;
import io.metersphere.api.mapper.ApiDefinitionBlobMapper;
import io.metersphere.api.mapper.ApiDefinitionFollowerMapper;
import io.metersphere.api.mapper.ApiDefinitionMapper;
import io.metersphere.api.mapper.ExtApiDefinitionMapper;
import io.metersphere.api.mapper.*;
import io.metersphere.api.service.ApiFileResourceService;
import io.metersphere.api.util.ApiDataUtils;
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
import io.metersphere.project.mapper.ExtBaseProjectVersionMapper;
import io.metersphere.project.service.ProjectService;
import io.metersphere.sdk.constants.ApplicationNumScope;
import io.metersphere.sdk.constants.StorageType;
import io.metersphere.sdk.constants.DefaultRepositoryDir;
import io.metersphere.sdk.constants.ModuleConstants;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.LogUtils;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.dto.table.TableBatchProcessDTO;
import io.metersphere.system.file.FileRequest;
import io.metersphere.system.file.MinioRepository;
import io.metersphere.system.service.UserLoginService;
import io.metersphere.system.uid.IDGenerator;
import io.metersphere.system.uid.NumGenerator;
@ -33,6 +30,7 @@ import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.util.*;
@ -41,13 +39,11 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
@Service
@Transactional(rollbackFor = Exception.class)
public class ApiDefinitionService {
public static final Long ORDER_STEP = 5000L;
private static final String MAIN_FOLDER_PROJECT = "project";
private static final String APP_NAME_API_DEFINITION = "apiDefinition";
@Resource
private ApiDefinitionMapper apiDefinitionMapper;
@ -64,17 +60,25 @@ public class ApiDefinitionService {
private ApiDefinitionBlobMapper apiDefinitionBlobMapper;
@Resource
private UserLoginService userLoginService;
private ExtApiTestCaseMapper extApiTestCaseMapper;
@Resource
private MinioRepository minioRepository;
private UserLoginService userLoginService;
@Resource
private SqlSessionFactory sqlSessionFactory;
@Resource
private ApiTestCaseService apiTestCaseService;
public List<ApiDefinitionDTO> getApiDefinitionPage(ApiDefinitionPageRequest request, Boolean deleted){
List<ApiDefinitionDTO> list = extApiDefinitionMapper.list(request, deleted);
@Resource
private ApiDefinitionLogService apiDefinitionLogService;
@Resource
private ApiFileResourceService apiFileResourceService;
public List<ApiDefinitionDTO> getApiDefinitionPage(ApiDefinitionPageRequest request){
List<ApiDefinitionDTO> list = extApiDefinitionMapper.list(request);
if (!CollectionUtils.isEmpty(list)) {
processApiDefinitions(list, request.getProjectId());
}
@ -83,16 +87,22 @@ public class ApiDefinitionService {
public ApiDefinitionDTO get(String id, String userId){
ApiDefinitionDTO apiDefinitionDTO = new ApiDefinitionDTO();
// 1. 避免重复查询数据库将查询结果传递给get方法
ApiDefinition apiDefinition = checkApiDefinition(id);
ApiDefinitionBlob apiDefinitionBlob = apiDefinitionBlobMapper.selectByPrimaryKey(id);
BeanUtils.copyBean(apiDefinitionDTO,apiDefinition);
// 2. 使用Optional避免空指针异常
Optional<ApiDefinitionBlob> apiDefinitionBlobOptional = Optional.ofNullable(apiDefinitionBlobMapper.selectByPrimaryKey(id));
apiDefinitionBlobOptional.ifPresent(blob -> {
apiDefinitionDTO.setRequest(ApiDataUtils.parseObject(new String(blob.getRequest()), AbstractMsTestElement.class));
// blob.getResponse() null 时不进行转换
if (blob.getResponse() != null) {
apiDefinitionDTO.setResponse(ApiDataUtils.parseArray(new String(blob.getResponse()), HttpResponse.class));
}
});
// 3. 使用Stream简化集合操作
ApiDefinitionFollowerExample example = new ApiDefinitionFollowerExample();
example.createCriteria().andApiDefinitionIdEqualTo(id).andUserIdEqualTo(userId);
List<ApiDefinitionFollower> followers = apiDefinitionFollowerMapper.selectByExample(example);
apiDefinitionDTO.setFollow(CollectionUtils.isNotEmpty(followers));
if(apiDefinitionBlob != null){
apiDefinitionDTO.setRequest(ApiDataUtils.parseObject(new String(apiDefinitionBlob.getRequest()), AbstractMsTestElement.class));
}
apiDefinitionDTO.setFollow(apiDefinitionFollowerMapper.countByExample(example) > 0);
BeanUtils.copyBean(apiDefinitionDTO, apiDefinition);
return apiDefinitionDTO;
}
@ -119,9 +129,21 @@ public class ApiDefinitionService {
ApiDefinitionBlob apiDefinitionBlob = new ApiDefinitionBlob();
apiDefinitionBlob.setId(apiDefinition.getId());
apiDefinitionBlob.setRequest(request.getRequest().getBytes());
apiDefinitionBlob.setResponse(request.getResponse().getBytes());
apiDefinitionBlobMapper.insertSelective(apiDefinitionBlob);
// TODO 文件只是上传到minio不需要入库吗
uploadBodyFile(bodyFiles, apiDefinition.getId(), request.getProjectId());
// 处理文件
if (CollectionUtils.isNotEmpty(request.getFileIds()) && CollectionUtils.isNotEmpty(bodyFiles)) {
String apiDefinitionDir = DefaultRepositoryDir.getApiDefinitionDir(request.getProjectId(), apiDefinition.getId());
ApiFileResourceUpdateRequest resourceUpdateRequest = new ApiFileResourceUpdateRequest();
resourceUpdateRequest.setProjectId(apiDefinition.getProjectId());
resourceUpdateRequest.setFileIds(request.getFileIds());
resourceUpdateRequest.setAddFileIds(request.getFileIds());
resourceUpdateRequest.setFolder(apiDefinitionDir);
resourceUpdateRequest.setResourceId(apiDefinition.getId());
resourceUpdateRequest.setApiResourceType(ApiResourceType.API);
apiFileResourceService.addFileResource(resourceUpdateRequest, bodyFiles);
}
return apiDefinition;
}
@ -130,7 +152,9 @@ public class ApiDefinitionService {
ApiDefinition originApiDefinition = checkApiDefinition(request.getId());
ApiDefinition apiDefinition = new ApiDefinition();
BeanUtils.copyBean(apiDefinition, request);
checkUpdateExist(apiDefinition, originApiDefinition);
if(request.getProtocol().equals(ModuleConstants.NODE_PROTOCOL_HTTP)){
checkUpdateExist(apiDefinition, originApiDefinition);
}
apiDefinition.setStatus(request.getStatus());
apiDefinition.setUpdateUser(userId);
apiDefinition.setUpdateTime(System.currentTimeMillis());
@ -142,16 +166,26 @@ public class ApiDefinitionService {
ApiDefinitionBlob apiDefinitionBlob = new ApiDefinitionBlob();
apiDefinitionBlob.setId(apiDefinition.getId());
apiDefinitionBlob.setRequest(request.getRequest().getBytes());
apiDefinitionBlob.setResponse(request.getResponse().getBytes());
apiDefinitionBlobMapper.updateByPrimaryKeySelective(apiDefinitionBlob);
// TODO 需要处理之前的文件
uploadBodyFile(bodyFiles, request.getId(), request.getProjectId());
// 处理文件
String apiDefinitionDir = DefaultRepositoryDir.getApiDefinitionDir(originApiDefinition.getProjectId(), apiDefinition.getId());
ApiFileResourceUpdateRequest resourceUpdateRequest = new ApiFileResourceUpdateRequest();
resourceUpdateRequest.setProjectId(originApiDefinition.getProjectId());
resourceUpdateRequest.setFileIds(request.getFileIds());
resourceUpdateRequest.setAddFileIds(request.getAddFileIds());
resourceUpdateRequest.setFolder(apiDefinitionDir);
resourceUpdateRequest.setResourceId(apiDefinition.getId());
resourceUpdateRequest.setApiResourceType(ApiResourceType.API);
apiFileResourceService.updateFileResource(resourceUpdateRequest, bodyFiles);
return apiDefinition;
}
public void batchUpdate(ApiDefinitionBatchUpdateRequest request, String userId) {
ProjectService.checkResourceExist(request.getProjectId());
List<String> ids = getBatchApiIds(request, request.getProjectId(), request.getProtocol());
List<String> ids = apiDefinitionLogService.getBatchApiIds(request, request.getProjectId(), request.getProtocol(), false);
if (CollectionUtils.isNotEmpty(ids)) {
if (request.getType().equals("tags")) {
handleTags(request, userId, ids);
@ -191,27 +225,27 @@ public class ApiDefinitionService {
apiDefinitionBlob.setResponse(copyApiDefinitionBlob.getResponse());
apiDefinitionBlobMapper.insertSelective(apiDefinitionBlob);
}
// TODO 复制的时候文件需要复制一份
// TODO 复制的时候文件需要复制一份 仅复制接口内容 不包含用例mock信息
return apiDefinition;
}
public void delete(ApiDefinitionDeleteRequest request, String userId) {
checkApiDefinition(request.getId());
handleDeleteApiDefinition(Collections.singletonList(request.getId()),request.getDeleteAll(), userId);
handleDeleteApiDefinition(Collections.singletonList(request.getId()),request.getDeleteAll(), request.getProjectId(), userId);
}
public void batchDelete(ApiDefinitionBatchRequest request, String userId) {
List<String> ids = getBatchApiIds(request, request.getProjectId(), request.getProtocol());
List<String> ids = apiDefinitionLogService.getBatchApiIds(request, request.getProjectId(), request.getProtocol(), false);
if (CollectionUtils.isNotEmpty(ids)) {
handleDeleteApiDefinition(ids, request.getDeleteAll(), userId);
handleDeleteApiDefinition(ids, request.getDeleteAll(), request.getProjectId(), userId);
}
}
public void batchMove(ApiDefinitionBatchMoveRequest request, String userId) {
List<String> ids = getBatchApiIds(request, request.getProjectId(), request.getProtocol());
List<String> ids = apiDefinitionLogService.getBatchApiIds(request, request.getProjectId(), request.getProtocol(), false);
if (!ids.isEmpty()) {
List<String> refIds = extApiDefinitionMapper.getRefIds(ids);
List<String> refIds = extApiDefinitionMapper.getRefIds(ids, false);
if (!refIds.isEmpty()) {
extApiDefinitionMapper.batchMove(request, refIds, userId);
}
@ -231,8 +265,15 @@ public class ApiDefinitionService {
item.setDeleteUserName(userMap.get(item.getDeleteUser()));
item.setUpdateUserName(userMap.get(item.getUpdateUser()));
// Convert tags
// Convert Blob
Optional<ApiDefinitionBlob> apiDefinitionBlobOptional = Optional.ofNullable(apiDefinitionBlobMapper.selectByPrimaryKey(item.getId()));
apiDefinitionBlobOptional.ifPresent(blob -> {
item.setRequest(ApiDataUtils.parseObject(new String(blob.getRequest()), AbstractMsTestElement.class));
// blob.getResponse() null 时不进行转换
if (blob.getResponse() != null) {
item.setResponse(ApiDataUtils.parseArray(new String(blob.getResponse()), HttpResponse.class));
}
});
// Calculate API Case Metrics
ApiCaseComputeDTO apiCaseComputeDTO = resultMap.get(item.getId());
if (apiCaseComputeDTO != null) {
@ -271,23 +312,6 @@ public class ApiDefinitionService {
return NumGenerator.nextNum(projectId, ApplicationNumScope.API_DEFINITION);
}
public void uploadBodyFile(List<MultipartFile> files, String apiId, String projectId) {
if (CollectionUtils.isNotEmpty(files)) {
files.forEach(file -> {
FileRequest fileRequest = new FileRequest();
fileRequest.setFileName(file.getName());
fileRequest.setFolder(minioPath(projectId));
fileRequest.setStorage(StorageType.MINIO.name());
try {
minioRepository.saveFile(file, fileRequest);
} catch (Exception e) {
LogUtils.info("上传body文件失败: 文件名称:" + file.getName(), e);
throw new MSException(Translator.get("file_upload_fail"));
}
});
}
}
/**
* 校验接口是否存在
*
@ -304,23 +328,23 @@ public class ApiDefinitionService {
private void checkAddExist(ApiDefinition apiDefinition) {
ApiDefinitionExample example = new ApiDefinitionExample();
example.createCriteria()
.andNameEqualTo(apiDefinition.getName())
.andModuleIdEqualTo(apiDefinition.getModuleId());
.andPathEqualTo(apiDefinition.getPath()).andMethodEqualTo(apiDefinition.getMethod())
.andModuleIdEqualTo(apiDefinition.getModuleId()).andProtocolEqualTo(apiDefinition.getProtocol());
if (CollectionUtils.isNotEmpty(apiDefinitionMapper.selectByExample(example))) {
throw new MSException(ApiResultCode.API_DEFINITION_EXIST);
}
}
private void checkUpdateExist(ApiDefinition apiDefinition, ApiDefinition originApiDefinition) {
if (StringUtils.isBlank(apiDefinition.getName())) {
if (StringUtils.isBlank(apiDefinition.getPath()) || StringUtils.isBlank(apiDefinition.getMethod())) {
return;
}
ApiDefinitionExample example = new ApiDefinitionExample();
example.createCriteria()
.andIdNotEqualTo(apiDefinition.getId())
.andIdNotEqualTo(apiDefinition.getId()).andProtocolEqualTo(apiDefinition.getProtocol())
.andModuleIdEqualTo(apiDefinition.getModuleId() == null ? originApiDefinition.getModuleId() : apiDefinition.getModuleId())
.andNameEqualTo(apiDefinition.getName());
if (CollectionUtils.isNotEmpty(apiDefinitionMapper.selectByExample(example))) {
.andPathEqualTo(apiDefinition.getPath()).andMethodEqualTo(apiDefinition.getMethod());
if (apiDefinitionMapper.countByExample(example) > 0) {
throw new MSException(ApiResultCode.API_DEFINITION_EXIST);
}
}
@ -331,19 +355,6 @@ public class ApiDefinitionService {
return apiDefinitionBlobMapper.selectByPrimaryKey(apiId);
}
public <T> List<String> getBatchApiIds(T dto, String projectId, String protocol) {
TableBatchProcessDTO request = (TableBatchProcessDTO) dto;
if (request.isSelectAll()) {
List<String> ids = extApiDefinitionMapper.getIds(request, projectId, protocol, false);
if (CollectionUtils.isNotEmpty(request.getExcludeIds())) {
ids.removeAll(request.getExcludeIds());
}
return ids;
} else {
return request.getSelectIds();
}
}
/**
* 根据接口id 获取接口是否存在多个版本
*
@ -372,7 +383,7 @@ public class ApiDefinitionService {
private void handleTags(ApiDefinitionBatchUpdateRequest request, String userId, List<String> ids) {
if (request.isAppend()) {
//追加标签
Map<String, ApiDefinition> collect = extApiDefinitionMapper.getTagsByIds(ids)
Map<String, ApiDefinition> collect = extApiDefinitionMapper.getTagsByIds(ids, false)
.stream()
.collect(Collectors.toMap(ApiDefinition::getId, Function.identity()));
try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) {
@ -415,27 +426,30 @@ public class ApiDefinitionService {
return copyName;
}
private void handleDeleteApiDefinition(List<String> ids, Boolean deleteAll, String userId) {
private void handleDeleteApiDefinition(List<String> ids, Boolean deleteAll, String projectId, String userId) {
if (deleteAll) {
//全部删除 进入回收站
List<String> refId = extApiDefinitionMapper.getRefIds(ids);
if(CollectionUtils.isNotEmpty(refId)){
extApiDefinitionMapper.batchDelete(refId, userId);
List<String> refIds = extApiDefinitionMapper.getRefIds(ids, false);
if(CollectionUtils.isNotEmpty(refIds)){
extApiDefinitionMapper.batchDeleteByRefId(refIds, userId, projectId);
List<String> delApiIds = extApiDefinitionMapper.getIdsByRefId(refIds, false);
if(CollectionUtils.isNotEmpty(delApiIds)){
// 删除接口相关数据到回收站
deleteApiRelatedData(delApiIds, userId, projectId);
}
}
} else {
//列表删除 需要判断是否存在多个版本问题
ids.forEach(id -> {
ApiDefinition apiDefinition = checkApiDefinition(id);
// 选中的数据直接放入回收站
doDelete(id, userId);
// 删除的数据是否为最新版本的数据如果是则需要查询是否有多版本数据存在需要去除当前删除的数据更新剩余版本数据中最近的一条数据为最新的数据
if(apiDefinition.getLatest()){
List<ApiDefinitionVersionDTO> apiDefinitionVersions = extApiDefinitionMapper.getApiDefinitionByRefId(apiDefinition.getRefId());
if (apiDefinitionVersions.size() > 1) {
deleteAfterAction(apiDefinitionVersions);
}
// 列表删除
// 选中的数据直接放入回收站
while (!ids.isEmpty()) {
if (ids.size() <= 2000) {
doDelete(ids, userId, projectId);
break;
}
});
List<String> subList = ids.subList(0, 2000);
doDelete(subList, userId, projectId);
ids.removeAll(subList);
}
}
}
@ -469,21 +483,165 @@ public class ApiDefinitionService {
extApiDefinitionMapper.updateLatestVersion(id, projectId);
}
private void doDelete(String id, String userId) {
ApiDefinition apiDefinition = new ApiDefinition();
apiDefinition.setDeleted(true);
apiDefinition.setId(id);
apiDefinition.setDeleteUser(userId);
apiDefinition.setDeleteTime(System.currentTimeMillis());
apiDefinitionMapper.updateByPrimaryKeySelective(apiDefinition);
private void doDelete(List<String> ids, String userId, String projectId) {
if(CollectionUtils.isNotEmpty(ids)){
extApiDefinitionMapper.batchDeleteById(ids, userId, projectId);
// 需要判断是否存在多个版本问题
ids.forEach(id -> {
ApiDefinition apiDefinition = checkApiDefinition(id);
// 删除的数据是否为最新版本的数据如果是则需要查询是否有多版本数据存在需要去除当前删除的数据更新剩余版本数据中最近的一条数据为最新的数据
if(apiDefinition.getLatest()){
List<ApiDefinitionVersionDTO> apiDefinitionVersions = extApiDefinitionMapper.getApiDefinitionByRefId(apiDefinition.getRefId());
if (apiDefinitionVersions.size() > 1) {
deleteAfterAction(apiDefinitionVersions);
}
}
});
// 删除 case
deleteApiRelatedData(ids, userId, projectId);
}
}
private void deleteApiRelatedData(List<String> apiIds, String userId, String projectId){
// 是否存在 case 删除 case
List<ApiTestCase> caseLists = extApiTestCaseMapper.getCaseInfoByApiIds(apiIds, false);
if(CollectionUtils.isNotEmpty(caseLists)){
List<String> caseIds = caseLists.stream().map(ApiTestCase::getId).distinct().toList();
apiTestCaseService.batchDeleteToGc(caseIds, userId, projectId, false);
}
// todo 删除文档到回收站
}
private void deleteFollower(String apiId, String userId) {
apiDefinitionFollowerMapper.deleteByPrimaryKey(apiId, userId);
}
public void restore(ApiDefinitionDeleteRequest request, String userId) {
// 恢复接口到接口列表
handleRestoreApiDefinition(Collections.singletonList(request.getId()), userId, request.getProjectId());
}
private void handleRestoreApiDefinition(List<String> ids, String userId, String projectId){
if (CollectionUtils.isNotEmpty(ids)) {
while (!ids.isEmpty()) {
if (ids.size() <= 2000) {
doRestore(ids, userId, projectId);
break;
}
List<String> subList = ids.subList(0, 2000);
doRestore(ids, userId, projectId);
ids.removeAll(subList);
}
}
}
private void doRestore(List<String> apiIds, String userId, String projectId) {
// 恢复接口
if(CollectionUtils.isNotEmpty(apiIds)){
extApiDefinitionMapper.batchRestoreById(apiIds, userId, projectId);
apiIds.forEach(id -> {
// 恢复数据恢复最新标识
ApiDefinition apiDefinition = checkApiDefinition(id);
// 判断是否存在多个版本
List<ApiDefinitionVersionDTO> apiDefinitionVersions = extApiDefinitionMapper.getApiDefinitionByRefId(apiDefinition.getRefId());
if (apiDefinitionVersions != null) {
if (apiDefinitionVersions.size() > 1) {
String defaultVersion = extBaseProjectVersionMapper.getDefaultVersion(apiDefinition.getProjectId());
// 清除所有最新标识
clearLatestVersion(apiDefinition.getRefId(), apiDefinition.getProjectId());
private String minioPath(String projectId) {
return StringUtils.join(MAIN_FOLDER_PROJECT, "/", projectId, "/", APP_NAME_API_DEFINITION);
// 获取最新数据恢复的数据最新标识则最新数据反之获取最新一条数据
ApiDefinition latestData = apiDefinition.getLatest() ?
apiDefinition : getLatestData(apiDefinition.getRefId(), apiDefinition.getProjectId());
// 恢复的数据不为最新标识同时接口版本为默认版本则更新此数据为最新标识
if (!latestData.getLatest()) {
updateLatestVersion(latestData.getVersionId().equals(defaultVersion) ?
apiDefinition.getId() : latestData.getId(), latestData.getProjectId());
}
}
}
});
// 恢复接口关联用例
recoverApiRelatedData(apiIds, userId, projectId);
}
}
private void recoverApiRelatedData(List<String> apiIds, String userId, String projectId){
// 是否存在 case 恢复 case
List<ApiTestCase> caseLists = extApiTestCaseMapper.getCaseInfoByApiIds(apiIds, false);
if(CollectionUtils.isNotEmpty(caseLists)) {
List<String> caseIds = caseLists.stream().map(ApiTestCase::getId).distinct().toList();
// todo case 批量恢复方法
LogUtils.info("caseIds" + JSON.toJSONString(caseIds));
// todo 恢复文档?
}
}
public void recycleDel(ApiDefinitionDeleteRequest request, String userId) {
handleRecycleDelApiDefinition(Collections.singletonList(request.getId()), userId, request.getProjectId(), false);
}
public void batchRestore(ApiDefinitionBatchRequest request, String userId) {
List<String> ids = apiDefinitionLogService.getBatchApiIds(request, request.getProjectId(), request.getProtocol(), true);
if (CollectionUtils.isNotEmpty(ids)) {
handleRestoreApiDefinition(ids, userId, request.getProjectId());
}
}
public void batchRecycleDel(ApiDefinitionBatchRequest request, String userId) {
List<String> ids = apiDefinitionLogService.getBatchApiIds(request, request.getProjectId(), request.getProtocol(), true);
if (CollectionUtils.isNotEmpty(ids)) {
handleRecycleDelApiDefinition(ids, userId, request.getProjectId(), true);
}
}
private void handleRecycleDelApiDefinition(List<String> ids, String userId, String projectId, Boolean isBatch){
if (CollectionUtils.isNotEmpty(ids)) {
while (!ids.isEmpty()) {
if (ids.size() <= 2000) {
doRecycleDel(ids, userId, projectId, isBatch);
break;
}
List<String> subList = ids.subList(0, 2000);
doRecycleDel(ids, userId, projectId, isBatch);
ids.removeAll(subList);
}
}
}
private void doRecycleDel(List<String> ids, String userId, String projectId, Boolean isBatch){
if(CollectionUtils.isNotEmpty(ids)){
ApiDefinitionExample apiDefinitionExample = new ApiDefinitionExample();
apiDefinitionExample.createCriteria().andIdIn(ids).andDeletedEqualTo(true).andProjectIdEqualTo(projectId);
List<ApiDefinition> apiDefinitions = apiDefinitionMapper.selectByExample(apiDefinitionExample);
// 删除接口
apiDefinitionMapper.deleteByExample(apiDefinitionExample);
// 删除接口关注人
ApiDefinitionFollowerExample apiDefinitionFollowerExample = new ApiDefinitionFollowerExample();
apiDefinitionFollowerExample.createCriteria().andApiDefinitionIdIn(ids).andUserIdEqualTo(userId);
apiDefinitionFollowerMapper.deleteByExample(apiDefinitionFollowerExample);
// 删除上传的文件
ids.forEach(id -> {
String apiDefinitionDir = DefaultRepositoryDir.getApiDefinitionDir(projectId, id);
apiFileResourceService.deleteByResourceId(apiDefinitionDir, id);
});
// 删除接口关联数据
recycleDelApiRelatedData(ids, userId, projectId);
// 写入删除日志
apiDefinitionLogService.recycleDelLog(apiDefinitions, userId, isBatch);
}
}
private void recycleDelApiRelatedData(List<String> apiIds, String userId, String projectId){
// 是否存在 case 删除 case
List<ApiTestCase> caseLists = extApiTestCaseMapper.getCaseInfoByApiIds(apiIds, true);
if(CollectionUtils.isNotEmpty(caseLists)) {
List<String> caseIds = caseLists.stream().map(ApiTestCase::getId).distinct().toList();
// case 批量删除回收站
apiTestCaseService.deleteResourceByIds(caseIds, projectId, userId);
// todo 删除文档?
}
}
}

View File

@ -5,9 +5,11 @@ import io.metersphere.api.domain.*;
import io.metersphere.api.dto.definition.*;
import io.metersphere.api.enums.ApiDefinitionStatus;
import io.metersphere.api.mapper.*;
import io.metersphere.api.service.ApiFileResourceService;
import io.metersphere.api.util.ApiDataUtils;
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
import io.metersphere.project.mapper.ExtBaseProjectVersionMapper;
import io.metersphere.sdk.constants.DefaultRepositoryDir;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.dto.api.request.http.MsHTTPElement;
import io.metersphere.sdk.util.BeanUtils;
@ -16,15 +18,16 @@ import io.metersphere.sdk.util.LogUtils;
import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.handler.ResultHolder;
import io.metersphere.system.dto.sdk.BaseCondition;
import io.metersphere.system.file.FileCenter;
import io.metersphere.system.file.FileRequest;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.uid.IDGenerator;
import io.metersphere.system.utils.Pager;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.jdbc.SqlConfig;
import org.springframework.test.web.servlet.MvcResult;
@ -32,7 +35,6 @@ import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import java.io.File;
import java.io.FileInputStream;
import java.nio.charset.StandardCharsets;
import java.util.*;
@ -49,16 +51,23 @@ public class ApiDefinitionControllerTests extends BaseTest {
private final static String UPDATE = BASE_PATH + "update";
private final static String BATCH_UPDATE = BASE_PATH + "batch-update";
private final static String DELETE = BASE_PATH + "delete";
private final static String BATCH_DELETE= BASE_PATH + "batch-del";
private final static String COPY= BASE_PATH + "copy";
private final static String BATCH_MOVE= BASE_PATH + "batch-move";
private final static String BATCH_DELETE = BASE_PATH + "batch-del";
private final static String COPY = BASE_PATH + "copy";
private final static String BATCH_MOVE = BASE_PATH + "batch-move";
private final static String PAGE= BASE_PATH + "page";
private final static String RESTORE = BASE_PATH + "restore";
private final static String BATCH_RESTORE = BASE_PATH + "batch-restore";
private final static String RECYCLE_DEL = BASE_PATH + "recycle-del";
private final static String BATCH_RECYCLE_DEL = BASE_PATH + "batch-recycle-del";
private final static String PAGE = BASE_PATH + "page";
private static final String GET = BASE_PATH + "get-detail/";
private static final String FOLLOW = BASE_PATH + "follow/";
private static final String VERSION = BASE_PATH + "version/";
private static final String DEFAULT_MODULE_ID = "10001";
private static ApiDefinition apiDefinition;
@Resource
private ApiDefinitionMapper apiDefinitionMapper;
@ -74,6 +83,12 @@ public class ApiDefinitionControllerTests extends BaseTest {
@Resource
private ExtBaseProjectVersionMapper extBaseProjectVersionMapper;
@Resource
private ApiFileResourceService apiFileResourceService;
@Resource
private ExtApiTestCaseMapper extApiTestCaseMapper;
@Test
@Order(1)
@ -83,13 +98,14 @@ public class ApiDefinitionControllerTests extends BaseTest {
ApiDefinitionAddRequest request = createApiDefinitionAddRequest();
MsHTTPElement msHttpElement = MsHTTPElementTest.getMsHttpElement();
request.setRequest(ApiDataUtils.toJSONString(msHttpElement));
List<HttpResponse> msHttpResponse = MsHTTPElementTest.getMsHttpResponse();
request.setResponse(ApiDataUtils.toJSONString(msHttpResponse));
// 构造请求参数
MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
paramMap.add("request", JSON.toJSONString(request));
FileInputStream inputStream = new FileInputStream(new File(
Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/file_upload.JPG"))
.getPath()));
MockMultipartFile file = new MockMultipartFile("file_upload.JPG", "file_upload.JPG", MediaType.APPLICATION_OCTET_STREAM_VALUE, inputStream);
File file = new File(
Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/file_upload.JPG")).getPath()
);
request.setFileIds(List.of(IDGenerator.nextStr()));
paramMap.add("files", List.of(file));
paramMap.add("request", JSON.toJSONString(request));
@ -97,14 +113,16 @@ public class ApiDefinitionControllerTests extends BaseTest {
MvcResult mvcResult = this.requestMultipartWithOkAndReturn(ADD, paramMap);
// 校验请求成功数据
ApiDefinition resultData = getResultData(mvcResult, ApiDefinition.class);
ApiDefinition apiDefinition = assertAddApiDefinition(request, msHttpElement, resultData.getId());
apiDefinition = assertAddApiDefinition(request, msHttpElement, resultData.getId(), request.getFileIds());
// 再插入一条数据便于修改时重名校验
request.setName("接口定义test-6");
request.setMethod("GET");
request.setPath("/api/admin/posts");
request.setFileIds(null);
paramMap.clear();
paramMap.add("request", JSON.toJSONString(request));
mvcResult = this.requestMultipartWithOkAndReturn(ADD, paramMap);
resultData = getResultData(mvcResult, ApiDefinition.class);
assertAddApiDefinition(request, msHttpElement, resultData.getId());
assertAddApiDefinition(request, msHttpElement, resultData.getId(), request.getFileIds());
// @@重名校验异常
assertErrorCode(this.requestMultipart(ADD, paramMap), ApiResultCode.API_DEFINITION_EXIST);
@ -122,7 +140,9 @@ public class ApiDefinitionControllerTests extends BaseTest {
// @@校验权限
request.setProjectId(DEFAULT_PROJECT_ID);
paramMap.clear();
request.setName("permission");
request.setName("permission-st-6");
request.setMethod("DELETE");
request.setPath("/api/admin/posts");
paramMap.add("request", JSON.toJSONString(request));
requestMultipartPermissionTest(PermissionConstants.PROJECT_API_DEFINITION_ADD, ADD, paramMap);
}
@ -137,14 +157,14 @@ public class ApiDefinitionControllerTests extends BaseTest {
request.setMethod("POST");
request.setPath("/api/admin/posts");
request.setStatus(ApiDefinitionStatus.PREPARE.getValue());
request.setModuleId("root");
request.setModuleId("default");
request.setVersionId(defaultVersion);
request.setDescription("描述内容");
request.setTags(new LinkedHashSet<>(List.of("tag1", "tag2")));
return request;
}
private ApiDefinition assertAddApiDefinition(Object request, MsHTTPElement msHttpElement, String id) {
private ApiDefinition assertAddApiDefinition(Object request, MsHTTPElement msHttpElement, String id, List<String> fileIds) throws Exception {
ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey(id);
ApiDefinitionBlob apiDefinitionBlob = apiDefinitionBlobMapper.selectByPrimaryKey(id);
ApiDefinition copyApiDefinition = BeanUtils.copyBean(new ApiDefinition(), apiDefinition);
@ -154,6 +174,26 @@ public class ApiDefinitionControllerTests extends BaseTest {
if(apiDefinitionBlob != null){
Assertions.assertEquals(msHttpElement, ApiDataUtils.parseObject(new String(apiDefinitionBlob.getRequest()), AbstractMsTestElement.class));
}
if (fileIds != null) {
// 验证文件的关联关系以及是否存入对象存储
List<ApiFileResource> apiFileResources = apiFileResourceService.getByResourceId(id);
Assertions.assertEquals(apiFileResources.size(), fileIds.size());
String apiDefinitionDir = DefaultRepositoryDir.getApiDefinitionDir(apiDefinition.getProjectId(), id);
FileRequest fileRequest = new FileRequest();
if (fileIds.size() > 0) {
for (ApiFileResource apiFileResource : apiFileResources) {
Assertions.assertEquals(apiFileResource.getProjectId(), apiDefinition.getProjectId());
fileRequest.setFolder(apiDefinitionDir + "/" + apiFileResource.getFileId());
fileRequest.setFileName(apiFileResource.getFileName());
Assertions.assertNotNull(FileCenter.getDefaultRepository().getFile(fileRequest));
}
fileRequest.setFolder(apiDefinitionDir);
} else {
fileRequest.setFolder(apiDefinitionDir);
Assertions.assertTrue(CollectionUtils.isEmpty(FileCenter.getDefaultRepository().getFolderFileNames(fileRequest)));
}
}
return apiDefinition;
}
@ -161,13 +201,15 @@ public class ApiDefinitionControllerTests extends BaseTest {
@Order(2)
@Sql(scripts = {"/dml/init_api_definition.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED))
public void get() throws Exception {
ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey("1001");
if(apiDefinition == null){
apiDefinition = apiDefinitionMapper.selectByPrimaryKey("1001");
}
// @@请求成功
MvcResult mvcResult = this.requestGetWithOkAndReturn(GET + apiDefinition.getId());
ApiDataUtils.setResolver(MsHTTPElement.class);
ApiDefinitionDTO apiDefinitionDTO = getResultData(mvcResult, ApiDefinitionDTO.class);
ApiDefinitionDTO apiDefinitionDTO = ApiDataUtils.parseObject(JSON.toJSONString(parseResponse(mvcResult).get("data")), ApiDefinitionDTO.class);
// 校验数据是否正确
ApiDefinitionDTO copyApiDefinitionDTO = BeanUtils.copyBean(new ApiDefinitionDTO(), apiDefinitionMapper.selectByPrimaryKey(apiDefinition.getId()));
ApiDefinitionDTO copyApiDefinitionDTO = BeanUtils.copyBean(new ApiDefinitionDTO(), apiDefinition);
ApiDefinitionBlob apiDefinitionBlob = apiDefinitionBlobMapper.selectByPrimaryKey(apiDefinition.getId());
ApiDefinitionFollowerExample example = new ApiDefinitionFollowerExample();
example.createCriteria().andApiDefinitionIdEqualTo(apiDefinition.getId()).andUserIdEqualTo("admin");
@ -175,6 +217,7 @@ public class ApiDefinitionControllerTests extends BaseTest {
copyApiDefinitionDTO.setFollow(CollectionUtils.isNotEmpty(followers));
if(apiDefinitionBlob != null){
copyApiDefinitionDTO.setRequest(ApiDataUtils.parseObject(new String(apiDefinitionBlob.getRequest()), AbstractMsTestElement.class));
copyApiDefinitionDTO.setResponse(ApiDataUtils.parseArray(new String(apiDefinitionBlob.getResponse()), HttpResponse.class));
}
Assertions.assertEquals(apiDefinitionDTO, copyApiDefinitionDTO);
@ -189,7 +232,9 @@ public class ApiDefinitionControllerTests extends BaseTest {
@Sql(scripts = {"/dml/init_api_definition.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED))
public void testUpdate() throws Exception {
LogUtils.info("update api test");
ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey("1001");
if(apiDefinition == null){
apiDefinition = apiDefinitionMapper.selectByPrimaryKey("1001");
}
ApiDefinitionUpdateRequest request = new ApiDefinitionUpdateRequest();
BeanUtils.copyBean(request, apiDefinition);
request.setPath("test.com/admin/test");
@ -198,14 +243,17 @@ public class ApiDefinitionControllerTests extends BaseTest {
request.setModuleId("default1");
MsHTTPElement msHttpElement = MsHTTPElementTest.getMsHttpElement();
request.setRequest(ApiDataUtils.toJSONString(msHttpElement));
List<HttpResponse> msHttpResponse = MsHTTPElementTest.getMsHttpResponse();
request.setResponse(ApiDataUtils.toJSONString(msHttpResponse));
// 构造请求参数
MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
paramMap.add("request", JSON.toJSONString(request));
FileInputStream inputStream = new FileInputStream(new File(
Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/file_update_upload.JPG"))
.getPath()));
MockMultipartFile file = new MockMultipartFile("file_update_upload.JPG", "file_update_upload.JPG", MediaType.APPLICATION_OCTET_STREAM_VALUE, inputStream);
File file = new File(
Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/file_update_upload.JPG")).getPath()
);
// 带文件的更新
request.setAddFileIds(List.of(IDGenerator.nextStr()));
request.setFileIds(request.getAddFileIds());
paramMap.add("files", List.of(file));
paramMap.add("request", JSON.toJSONString(request));
@ -213,7 +261,36 @@ public class ApiDefinitionControllerTests extends BaseTest {
MvcResult mvcResult = this.requestMultipartWithOkAndReturn(UPDATE, paramMap);
// 校验请求成功数据
ApiDefinition resultData = getResultData(mvcResult, ApiDefinition.class);
apiDefinition = assertAddApiDefinition(request, msHttpElement, resultData.getId());
apiDefinition = assertAddApiDefinition(request, msHttpElement, resultData.getId(), request.getFileIds());
// 删除了上一次上传的文件重新上传一个文件
request.setAddFileIds(List.of(IDGenerator.nextStr()));
request.setFileIds(request.getAddFileIds());
paramMap.clear();
paramMap.add("files", List.of(file));
paramMap.add("request", JSON.toJSONString(request));
this.requestMultipartWithOk(UPDATE, paramMap);
assertAddApiDefinition(request, msHttpElement, request.getId(), request.getFileIds());
// 已有一个文件再上传一个文件
request.setAddFileIds(List.of(IDGenerator.nextStr()));
List<String> fileIds = apiFileResourceService.getFileIdsByResourceId(request.getId());
fileIds.addAll(request.getAddFileIds());
request.setFileIds(fileIds);
paramMap.clear();
paramMap.add("files", List.of(file));
paramMap.add("request", JSON.toJSONString(request));
this.requestMultipartWithOk(UPDATE, paramMap);
assertAddApiDefinition(request, msHttpElement, request.getId(), request.getFileIds());
// @@重名校验异常
request.setModuleId("default");
request.setPath("/api/admin/posts");
request.setMethod("GET");
paramMap.clear();
paramMap.add("request", JSON.toJSONString(request));
assertErrorCode(this.requestMultipart(UPDATE, paramMap), ApiResultCode.API_DEFINITION_EXIST);
// 校验数据是否存在
request.setId("111");
request.setName("test123");
@ -235,7 +312,7 @@ public class ApiDefinitionControllerTests extends BaseTest {
// @@校验权限
request.setProjectId(DEFAULT_PROJECT_ID);
paramMap.clear();
request.setName("permission");
request.setName("permission-st-6");
paramMap.add("request", JSON.toJSONString(request));
requestMultipartPermissionTest(PermissionConstants.PROJECT_API_DEFINITION_UPDATE, UPDATE, paramMap);
}
@ -334,6 +411,8 @@ public class ApiDefinitionControllerTests extends BaseTest {
request.setId(apiDefinition.getId());
MvcResult mvcResult = this.requestPostWithOkAndReturn(COPY, request);
ApiDefinition resultData = getResultData(mvcResult, ApiDefinition.class);
// @数据验证
Assertions.assertEquals("copy_" + apiDefinition.getName(), resultData.getName());
// @@校验日志
checkLog(resultData.getId(), OperationLogType.UPDATE);
request.setId("121");
@ -428,7 +507,9 @@ public class ApiDefinitionControllerTests extends BaseTest {
@Sql(scripts = {"/dml/init_api_definition.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED))
public void testDel() throws Exception {
LogUtils.info("delete api test");
ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey("1001");
if(apiDefinition == null){
apiDefinition = apiDefinitionMapper.selectByPrimaryKey("1001");
}
// @只存在一个版本
ApiDefinitionDeleteRequest apiDefinitionDeleteRequest = new ApiDefinitionDeleteRequest();
apiDefinitionDeleteRequest.setId(apiDefinition.getId());
@ -504,17 +585,16 @@ public class ApiDefinitionControllerTests extends BaseTest {
request.setProjectId(DEFAULT_PROJECT_ID);
// 删除选中
request.setSelectIds(List.of("1001","1002","1005"));
request.setExcludeIds(List.of("1005"));
request.setSelectIds(List.of("1002","1004"));
request.setDeleteAll(false);
request.setSelectAll(false);
this.requestPostWithOkAndReturn(BATCH_DELETE, request);
// @@校验日志
checkLog("1001", OperationLogType.DELETE);
checkLog("1002", OperationLogType.DELETE);
checkLog("1005", OperationLogType.DELETE);
checkLog("1004", OperationLogType.DELETE);
// 删除全部 条件为关键字为st-6的数据
request.setDeleteAll(true);
request.setExcludeIds(List.of("1005"));
request.setSelectAll(true);
BaseCondition baseCondition = new BaseCondition();
baseCondition.setKeyword("st-6");
@ -531,54 +611,7 @@ public class ApiDefinitionControllerTests extends BaseTest {
@Order(11)
@Sql(scripts = {"/dml/init_api_definition.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED))
public void getPage() throws Exception {
ApiDefinitionPageRequest request = new ApiDefinitionPageRequest();
request.setProjectId(DEFAULT_PROJECT_ID);
request.setCurrent(1);
request.setPageSize(10);
this.requestPost(PAGE, request);
request.setSort(new HashMap<>() {{
put("createTime", "asc");
}});
// ALL 全部 KEYWORD 关键字 FILTER 筛选 COMBINE 自定义
String search = "KEYWORD";
Map<String, List<String>> filters = new HashMap<>();
Map<String, Object> map = new HashMap<>();
switch (search) {
case "ALL":
// Perform all search types
request.setKeyword("100");
filters.put("status", Arrays.asList("Underway", "Completed"));
filters.put("method", List.of("GET"));
filters.put("version_id", List.of("1005704995741369851"));
request.setFilter(filters);
map.put("name", Map.of("operator", "like", "value", "test-1"));
map.put("method", Map.of("operator", "in", "value", Arrays.asList("GET", "POST")));
request.setCombine(map);
break;
case "KEYWORD":
// 基础查询
request.setKeyword("100");
// 版本查询
request.setVersionId("100570499574136985");
break;
case "FILTER":
// 筛选
filters.put("status", Arrays.asList("Underway", "Completed"));
filters.put("method", List.of("GET"));
filters.put("version_id", List.of("1005704995741369851"));
request.setFilter(filters);
break;
case "COMBINE":
// 自定义字段 测试
map.put("name", Map.of("operator", "like", "value", "test-1"));
map.put("method", Map.of("operator", "in", "value", Arrays.asList("GET", "POST")));
request.setCombine(map);
break;
default:
break;
}
ApiDefinitionPageRequest request = createApiDefinitionPageRequest();
MvcResult mvcResult = this.requestPostWithOkAndReturn(PAGE, request);
// 获取返回值
@ -595,4 +628,236 @@ public class ApiDefinitionControllerTests extends BaseTest {
Assertions.assertTrue(JSON.parseArray(JSON.toJSONString(pageData.getList())).size() <= request.getPageSize());
}
private ApiDefinitionPageRequest createApiDefinitionPageRequest() {
ApiDefinitionPageRequest request = new ApiDefinitionPageRequest();
request.setProjectId(DEFAULT_PROJECT_ID);
request.setCurrent(1);
request.setPageSize(10);
request.setSort(Map.of("createTime", "asc"));
String search = getRandomSearchType();
switch (search) {
case "ALL" -> configureAllSearch(request);
case "KEYWORD" -> configureKeywordSearch(request);
case "FILTER" -> configureFilterSearch(request);
case "COMBINE" -> configureCombineSearch(request);
default -> {}
}
return request;
}
private String getRandomSearchType() {
List<String> searchTypes = Arrays.asList("ALL", "KEYWORD", "FILTER", "COMBINE");
return searchTypes.get(new Random().nextInt(searchTypes.size()));
}
private void configureAllSearch(ApiDefinitionPageRequest request) {
request.setKeyword("100");
Map<String, List<String>> filters = new HashMap<>();
filters.put("status", Arrays.asList("Underway", "Completed"));
filters.put("method", List.of("GET"));
filters.put("version_id", List.of("1005704995741369851"));
request.setFilter(filters);
Map<String, Object> map = new HashMap<>();
map.put("name", Map.of("operator", "like", "value", "test-1"));
map.put("method", Map.of("operator", "in", "value", Arrays.asList("GET", "POST")));
request.setCombine(map);
}
private void configureKeywordSearch(ApiDefinitionPageRequest request) {
request.setKeyword("100");
request.setVersionId("100570499574136985");
}
private void configureFilterSearch(ApiDefinitionPageRequest request) {
Map<String, List<String>> filters = new HashMap<>();
filters.put("status", Arrays.asList("Underway", "Completed"));
filters.put("method", List.of("GET"));
filters.put("version_id", List.of("1005704995741369851"));
request.setFilter(filters);
}
private void configureCombineSearch(ApiDefinitionPageRequest request) {
Map<String, Object> map = new HashMap<>();
map.put("name", Map.of("operator", "like", "value", "test-1"));
map.put("method", Map.of("operator", "in", "value", Arrays.asList("GET", "POST")));
request.setCombine(map);
}
@Test
@Order(12)
@Sql(scripts = {"/dml/init_api_definition.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED))
public void testRestore() throws Exception {
LogUtils.info("restore api test");
if(apiDefinition == null){
apiDefinition = apiDefinitionMapper.selectByPrimaryKey("1001");
}
// @恢复一条数据
ApiDefinitionDeleteRequest apiDefinitionDeleteRequest = new ApiDefinitionDeleteRequest();
apiDefinitionDeleteRequest.setId(apiDefinition.getId());
apiDefinitionDeleteRequest.setProjectId(DEFAULT_PROJECT_ID);
// @@请求成功
this.requestPostWithOkAndReturn(RESTORE, apiDefinitionDeleteRequest);
checkLog(apiDefinition.getId(), OperationLogType.UPDATE);
ApiDefinition apiDefinitionInfo = apiDefinitionMapper.selectByPrimaryKey(apiDefinition.getId());
Assertions.assertFalse(apiDefinitionInfo.getDeleted());
Assertions.assertNull(apiDefinitionInfo.getDeleteUser());
Assertions.assertNull(apiDefinitionInfo.getDeleteTime());
// @查询恢复的数据版本是否为默认版本
String defaultVersion = extBaseProjectVersionMapper.getDefaultVersion(apiDefinition.getProjectId());
if(defaultVersion.equals(apiDefinition.getVersionId())){
// 需要处理此数据为最新标识
// 此数据不为最新版本验证是否更新为最新版本
if(!apiDefinition.getLatest()){
Assertions.assertTrue(apiDefinitionInfo.getLatest());
}
}
// todo 效验 关联数据
// List<ApiTestCase> caseLists = extApiTestCaseMapper.getCaseInfoByApiIds(Collections.singletonList(apiDefinition.getId()), false);
// if(!caseLists.isEmpty()) {
// caseLists.forEach(item -> {
// Assertions.assertFalse(item.getDeleted());
// Assertions.assertNull(item.getDeleteUser());
// Assertions.assertNull(item.getDeleteTime());
// });
// }
// @@校验权限
requestPostPermissionTest(PermissionConstants.PROJECT_API_DEFINITION_UPDATE, RESTORE, apiDefinitionDeleteRequest);
}
@Test
@Order(13)
@Sql(scripts = {"/dml/init_api_definition.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED))
public void testRecycleDel() throws Exception {
LogUtils.info("recycleDel api test");
if(apiDefinition == null){
apiDefinition = apiDefinitionMapper.selectByPrimaryKey("1001");
}
if(!apiDefinition.getDeleted()){
testDel();
}
// @只存在一个版本
ApiDefinitionDeleteRequest apiDefinitionDeleteRequest = new ApiDefinitionDeleteRequest();
apiDefinitionDeleteRequest.setId(apiDefinition.getId());
apiDefinitionDeleteRequest.setProjectId(DEFAULT_PROJECT_ID);
apiDefinitionDeleteRequest.setDeleteAll(false);
// @@请求成功
this.requestPostWithOkAndReturn(RECYCLE_DEL, apiDefinitionDeleteRequest);
checkLog(apiDefinition.getId(), OperationLogType.DELETE);
// 验证数据
ApiDefinition apiDefinitionInfo = apiDefinitionMapper.selectByPrimaryKey(apiDefinition.getId());
Assertions.assertNull(apiDefinitionInfo);
// 文件是否删除
List<ApiFileResource> apiFileResources = apiFileResourceService.getByResourceId(apiDefinition.getId());
Assertions.assertEquals(0, apiFileResources.size());
// 效验 关联数据
List<ApiTestCase> caseLists = extApiTestCaseMapper.getCaseInfoByApiIds(Collections.singletonList(apiDefinition.getId()), false);
Assertions.assertEquals(0, caseLists.size());
// @@校验权限
requestPostPermissionTest(PermissionConstants.PROJECT_API_DEFINITION_DELETE, RECYCLE_DEL, apiDefinitionDeleteRequest);
}
@Test
@Order(14)
@Sql(scripts = {"/dml/init_api_definition.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED))
public void testBatchRestore() throws Exception {
LogUtils.info("batch restore api test");
ApiDefinitionBatchRequest request = new ApiDefinitionBatchRequest();
request.setProjectId(DEFAULT_PROJECT_ID);
// 恢复选中
request.setSelectIds(List.of("1002","1004","1005"));
request.setExcludeIds(List.of("1005"));
request.setSelectAll(false);
this.requestPostWithOkAndReturn(BATCH_RESTORE, request);
// 效验数据结果
ApiDefinitionExample apiDefinitionExample = new ApiDefinitionExample();
apiDefinitionExample.createCriteria().andIdIn(request.getSelectIds());
List<ApiDefinition> apiDefinitions = apiDefinitionMapper.selectByExample(apiDefinitionExample);
if(!apiDefinitions.isEmpty()){
apiDefinitions.forEach(item -> {
Assertions.assertFalse(item.getDeleted());
Assertions.assertNull(item.getDeleteUser());
Assertions.assertNull(item.getDeleteTime());
// todo 效验 关联数据
// List<ApiTestCase> caseLists = extApiTestCaseMapper.getCaseInfoByApiIds(Collections.singletonList(item.getId()), false);
// if(!caseLists.isEmpty()) {
// caseLists.forEach(test -> {
// Assertions.assertFalse(test.getDeleted());
// Assertions.assertNull(test.getDeleteUser());
// Assertions.assertNull(test.getDeleteTime());
// });
// }
});
}
// @@校验日志
checkLog("1002", OperationLogType.UPDATE);
checkLog("1004", OperationLogType.UPDATE);
checkLog("1005", OperationLogType.UPDATE);
// 恢复全部 条件为关键字为st-6的数据
request.setSelectAll(true);
BaseCondition baseCondition = new BaseCondition();
baseCondition.setKeyword("st-6");
request.setCondition(baseCondition);
this.requestPostWithOkAndReturn(BATCH_RESTORE, request);
// @@校验日志
checkLog("1006", OperationLogType.UPDATE);
// @@校验权限
requestPostPermissionTest(PermissionConstants.PROJECT_API_DEFINITION_UPDATE, BATCH_RESTORE, request);
}
@Test
@Order(15)
@Sql(scripts = {"/dml/init_api_definition.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED))
public void testBatchRecycleDel() throws Exception {
LogUtils.info("batch recycle delete api test");
testBatchDel();
ApiDefinitionBatchRequest request = new ApiDefinitionBatchRequest();
request.setProjectId(DEFAULT_PROJECT_ID);
// 删除选中
request.setSelectIds(List.of("1002","1004"));
request.setSelectAll(false);
this.requestPostWithOkAndReturn(BATCH_RECYCLE_DEL, request);
// 效验数据结果
ApiDefinitionExample apiDefinitionExample = new ApiDefinitionExample();
apiDefinitionExample.createCriteria().andIdIn(request.getSelectIds());
List<ApiDefinition> apiDefinitions = apiDefinitionMapper.selectByExample(apiDefinitionExample);
Assertions.assertEquals(0, apiDefinitions.size());
request.getSelectIds().forEach(item -> {
// 文件是否删除
List<ApiFileResource> apiFileResources = apiFileResourceService.getByResourceId(item);
Assertions.assertEquals(0, apiFileResources.size());
});
// 效验 关联数据
List<ApiTestCase> caseLists = extApiTestCaseMapper.getCaseInfoByApiIds(request.getSelectIds(), false);
Assertions.assertEquals(0, caseLists.size());
// @@校验日志
checkLog("1002", OperationLogType.DELETE);
checkLog("1004", OperationLogType.DELETE);
// 删除全部 条件为关键字为st-6的数据
request.setSelectAll(true);
request.setExcludeIds(List.of("1005"));
BaseCondition baseCondition = new BaseCondition();
baseCondition.setKeyword("st-6");
request.setCondition(baseCondition);
this.requestPostWithOkAndReturn(BATCH_RECYCLE_DEL, request);
// @@校验日志
checkLog("1006", OperationLogType.DELETE);
// @@校验权限
requestPostPermissionTest(PermissionConstants.PROJECT_API_DEFINITION_DELETE, BATCH_RECYCLE_DEL, request);
}
}

View File

@ -1,5 +1,7 @@
package io.metersphere.api.controller;
import io.metersphere.sdk.dto.api.request.http.body.Body;
import io.metersphere.api.dto.definition.HttpResponse;
import io.metersphere.api.util.ApiDataUtils;
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
import io.metersphere.sdk.dto.api.request.http.*;
@ -187,4 +189,38 @@ public class MsHTTPElementTest {
return msHTTPElement;
}
public static List<HttpResponse> getMsHttpResponse() {
List<HttpResponse> httpResponses = new ArrayList<>();
HttpResponse httpResponse = new HttpResponse();
httpResponse.setId(1);
httpResponse.setName("Response1");
httpResponse.setStatusCode("200");
httpResponse.setDefaultFlag(true);
Header header = new Header();
header.setEnable(false);
header.setValue("value");
header.setKey("key");
header.setDescription("desc");
httpResponse.setHeaders(List.of(header));
FormDataBody formDataBody = new FormDataBody();
FormDataKV formDataKV = new FormDataKV();
formDataKV.setEnable(false);
formDataKV.setContentType("text/plain");
formDataKV.setEncode(true);
formDataKV.setMaxLength(10);
formDataKV.setMinLength(8);
formDataKV.setParamType("text");
formDataKV.setDescription("test");
formDataKV.setRequired(true);
formDataKV.setValue("value");
formDataKV.setKey("key");
formDataBody.setFromValues(List.of(formDataKV));
httpResponse.setBody(formDataBody);
httpResponses.add(httpResponse);
return httpResponses;
}
}

View File

@ -5,7 +5,7 @@ INSERT INTO `api_definition` (`id`, `name`, `protocol`, `method`, `path`, `statu
INSERT INTO `api_definition` (`id`, `name`, `protocol`, `method`, `path`, `status`, `num`, `tags`, `pos`, `project_id`, `module_id`, `latest`, `version_id`, `ref_id`, `description`, `create_time`, `create_user`, `update_time`, `update_user`, `delete_user`, `delete_time`, `deleted`) VALUES ('1002', 'test-2', 'HTTP', 'GET', '/api/admin/2', 'Underway', 1002, '[\"test2\",\"te\"]', 1, '100001100001', 'root', b'1', '1005704995741369851', '1002', NULL, 1699500298164, 'admin', 1699500298164, 'admin', NULL, NULL, b'0');
INSERT INTO `api_definition` (`id`, `name`, `protocol`, `method`, `path`, `status`, `num`, `tags`, `pos`, `project_id`, `module_id`, `latest`, `version_id`, `ref_id`, `description`, `create_time`, `create_user`, `update_time`, `update_user`, `delete_user`, `delete_time`, `deleted`) VALUES ('1003', 'test-3', 'HTTP', 'POST', '/api/admin/3', 'Completed', 1003, '[\"test3\",\"te\"]', 1, '100001100001', 'root', b'1', '100570499574136985', '1002', NULL, 1699500298164, 'admin', 1699500298164, 'admin', NULL, NULL, b'0');
INSERT INTO `api_definition` (`id`, `name`, `protocol`, `method`, `path`, `status`, `num`, `tags`, `pos`, `project_id`, `module_id`, `latest`, `version_id`, `ref_id`, `description`, `create_time`, `create_user`, `update_time`, `update_user`, `delete_user`, `delete_time`, `deleted`) VALUES ('1004', 'test-4', 'HTTP', 'GET', '/api/admin/4', 'Prepare', 1004, '[\"test4\",\"te\"]', 1, '100001100001', 'root', b'1', '1005704995741369851', '1004', NULL, 1699500298164, 'admin', 1699500298164, 'admin', NULL, NULL, b'0');
INSERT INTO `api_definition` (`id`, `name`, `protocol`, `method`, `path`, `status`, `num`, `tags`, `pos`, `project_id`, `module_id`, `latest`, `version_id`, `ref_id`, `description`, `create_time`, `create_user`, `update_time`, `update_user`, `delete_user`, `delete_time`, `deleted`) VALUES ('1005', 'test-5', 'HTTP', 'POST', '/api/admin/5', 'Underway', 1005, '[\"test5\",\"te\"]', 1, '100001100001', 'root', b'0', '1005704995741369851', '1004', NULL, 1699500298164, 'admin', 1699500298164, 'admin', NULL, NULL, b'0');
INSERT INTO `api_definition` (`id`, `name`, `protocol`, `method`, `path`, `status`, `num`, `tags`, `pos`, `project_id`, `module_id`, `latest`, `version_id`, `ref_id`, `description`, `create_time`, `create_user`, `update_time`, `update_user`, `delete_user`, `delete_time`, `deleted`) VALUES ('1005', 'test-65', 'HTTP', 'POST', '/api/admin/5', 'Underway', 1005, '[\"test5\",\"te\"]', 1, '100001100001', 'root', b'0', '1005704995741369851', '1004', NULL, 1699500298164, 'admin', 1699500298164, 'admin', NULL, NULL, b'0');
INSERT INTO `api_definition` (`id`, `name`, `protocol`, `method`, `path`, `status`, `num`, `tags`, `pos`, `project_id`, `module_id`, `latest`, `version_id`, `ref_id`, `description`, `create_time`, `create_user`, `update_time`, `update_user`, `delete_user`, `delete_time`, `deleted`) VALUES ('1006', 'test-6', 'HTTP', 'GET', '/api/admin/6', 'Completed', 1006, '[\"test6\",\"te\"]', 1, '100001100001', 'root', b'1', '100570499574136985', '1006', NULL, 1699500298164, 'admin', 1699500298164, 'admin', NULL, NULL, b'0');
DELETE FROM `project_version` WHERE `id` = '100570499574136985';
@ -14,10 +14,10 @@ INSERT INTO project_version (id, project_id, name, description, status, latest,
DELETE FROM `api_test_case` WHERE `id` in ('12df5721-c5e6-a38b-e999-3eafcb992094','12df5721-c5e6-a38b-e999-3eafcb992100','12df5721-c5e6-a38b-e999-3eafcb992233','3ee2ae9c-a680-4ed6-b115-1f6ab8980973','3ee2ae9c-a680-4ed6-b115-1f6ab8980100','3ee2ae9c-a680-4ed6-b115-1f6ab8980589');
INSERT INTO `api_test_case` (`id`, `name`, `priority`, `num`, `tags`, `status`, `last_report_status`, `last_report_id`, `pos`, `project_id`, `api_definition_id`, `version_id`, `environment_id`, `create_time`, `create_user`, `update_time`, `update_user`, `delete_time`, `delete_user`, `deleted`) VALUES ('12df5721-c5e6-a38b-e999-3eafcb992094', '查询windows主机', 'P0', 100002001, NULL, 'PENDING', NULL, '10001', 10000, '100001100001', '1001', '100570499574136985', 'admin', 1699500298164, 'admin', 1699500298164, 'admin', NULL, NULL, b'0');
INSERT INTO `api_test_case` (`id`, `name`, `priority`, `num`, `tags`, `status`, `last_report_status`, `last_report_id`, `pos`, `project_id`, `api_definition_id`, `version_id`, `environment_id`, `create_time`, `create_user`, `update_time`, `update_user`, `delete_time`, `delete_user`, `deleted`) VALUES ('12df5721-c5e6-a38b-e999-3eafcb992100', '查询windows主机', 'P0', 100002002, NULL, 'PENDING', NULL, '10002', 10000, '100001100001', '1001', '100570499574136985', 'admin', 1699500298164, 'admin', 1699500298164, 'admin', NULL, NULL, b'0');
INSERT INTO `api_test_case` (`id`, `name`, `priority`, `num`, `tags`, `status`, `last_report_status`, `last_report_id`, `pos`, `project_id`, `api_definition_id`, `version_id`, `environment_id`, `create_time`, `create_user`, `update_time`, `update_user`, `delete_time`, `delete_user`, `deleted`) VALUES ('12df5721-c5e6-a38b-e999-3eafcb992233', '查询windows主机', 'P0', 100002003, NULL, 'PENDING', NULL, '10003', 10000, '100001100001', '1001', '100570499574136985', 'admin', 1699500298164, 'admin', 1699500298164, 'admin', NULL, NULL, b'0');
INSERT INTO `api_test_case` (`id`, `name`, `priority`, `num`, `tags`, `status`, `last_report_status`, `last_report_id`, `pos`, `project_id`, `api_definition_id`, `version_id`, `environment_id`, `create_time`, `create_user`, `update_time`, `update_user`, `delete_time`, `delete_user`, `deleted`) VALUES ('12df5721-c5e6-a38b-e999-3eafcb992233', '查询windows主机', 'P0', 100002003, NULL, 'PENDING', NULL, '10003', 10000, '100001100001', '1002', '100570499574136985', 'admin', 1699500298164, 'admin', 1699500298164, 'admin', NULL, NULL, b'0');
INSERT INTO `api_test_case` (`id`, `name`, `priority`, `num`, `tags`, `status`, `last_report_status`, `last_report_id`, `pos`, `project_id`, `api_definition_id`, `version_id`, `environment_id`, `create_time`, `create_user`, `update_time`, `update_user`, `delete_time`, `delete_user`, `deleted`) VALUES ('3ee2ae9c-a680-4ed6-b115-1f6ab8980973', '查询Linux主机', 'P0', 100002004, NULL, 'PENDING', NULL, '10004', 10000, '100001100001', '1002', '100570499574136985', 'admin', 1699500298164, 'admin', 1699500298164, 'admin', NULL, NULL, b'0');
INSERT INTO `api_test_case` (`id`, `name`, `priority`, `num`, `tags`, `status`, `last_report_status`, `last_report_id`, `pos`, `project_id`, `api_definition_id`, `version_id`, `environment_id`, `create_time`, `create_user`, `update_time`, `update_user`, `delete_time`, `delete_user`, `deleted`) VALUES ('3ee2ae9c-a680-4ed6-b115-1f6ab8980100', '查询Linux主机', 'P0', 100002005, NULL, 'PENDING', NULL, '10005', 10000, '100001100001', '1002', '100570499574136985', 'admin', 1699500298164, 'admin', 1699500298164, 'admin', NULL, NULL, b'0');
INSERT INTO `api_test_case` (`id`, `name`, `priority`, `num`, `tags`, `status`, `last_report_status`, `last_report_id`, `pos`, `project_id`, `api_definition_id`, `version_id`, `environment_id`, `create_time`, `create_user`, `update_time`, `update_user`, `delete_time`, `delete_user`, `deleted`) VALUES ('3ee2ae9c-a680-4ed6-b115-1f6ab8980589', '查询Linux主机', 'P0', 100002006, NULL, 'PENDING', NULL, '10006', 10000, '100001100001', '1002', '100570499574136985', 'admin', 1699500298164, 'admin', 1699500298164, 'admin', NULL, NULL, b'0');
INSERT INTO `api_test_case` (`id`, `name`, `priority`, `num`, `tags`, `status`, `last_report_status`, `last_report_id`, `pos`, `project_id`, `api_definition_id`, `version_id`, `environment_id`, `create_time`, `create_user`, `update_time`, `update_user`, `delete_time`, `delete_user`, `deleted`) VALUES ('3ee2ae9c-a680-4ed6-b115-1f6ab8980100', '查询Linux主机', 'P0', 100002005, NULL, 'PENDING', NULL, '10005', 10000, '100001100001', '1003', '100570499574136985', 'admin', 1699500298164, 'admin', 1699500298164, 'admin', NULL, NULL, b'0');
INSERT INTO `api_test_case` (`id`, `name`, `priority`, `num`, `tags`, `status`, `last_report_status`, `last_report_id`, `pos`, `project_id`, `api_definition_id`, `version_id`, `environment_id`, `create_time`, `create_user`, `update_time`, `update_user`, `delete_time`, `delete_user`, `deleted`) VALUES ('3ee2ae9c-a680-4ed6-b115-1f6ab8980589', '查询Linux主机', 'P0', 100002006, NULL, 'PENDING', NULL, '10006', 10000, '100001100001', '1004', '100570499574136985', 'admin', 1699500298164, 'admin', 1699500298164, 'admin', NULL, NULL, b'0');
DELETE FROM `api_report` WHERE `id` in ('10001','10002','10003','10004','10005','10006');
INSERT INTO `api_report` (`id`, `name`, `resource_id`, `create_time`, `update_time`, `create_user`, `update_user`, `deleted`, `status`, `start_time`, `end_time`, `run_mode`, `pool_id`, `trigger_mode`, `version_id`, `project_id`, `integrated_report_id`, `integrated`) VALUES ('10001', '报告001', 'resource_id_10001', 1680624405386, 1680624405386, 'admin', 'admin', b'0', 'SUCCESS', 1680624405386, 1680624405386, 'API', 'pol_id_100001', 'hand', NULL, '100001100001', 'NONE', b'0');