feat(接口测试): 接口管理模块接口文档分享

This commit is contained in:
lan-yonghui 2023-12-29 14:53:05 +08:00 committed by Craftsman
parent ca1217b724
commit 6be702af86
16 changed files with 484 additions and 17 deletions

View File

@ -156,3 +156,17 @@ CREATE INDEX idx_type ON operation_history (`type`);
-- set innodb lock wait timeout to default
SET SESSION innodb_lock_wait_timeout = DEFAULT;
CREATE TABLE IF NOT EXISTS share_info
(
`id` VARCHAR(50) NOT NULL COMMENT '分享ID' ,
`create_time` BIGINT NOT NULL COMMENT '创建时间' ,
`create_user` VARCHAR(50) NOT NULL COMMENT '创建人' ,
`update_time` BIGINT NOT NULL COMMENT '更新时间' ,
`share_type` VARCHAR(64) COMMENT '分享类型single batch' ,
`custom_data` LONGBLOB COMMENT '分享扩展数据' ,
`lang` VARCHAR(10) COMMENT '语言' ,
PRIMARY KEY (id)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_general_ci COMMENT = '分享';

View File

@ -44,6 +44,7 @@ public class FilterChainUtils {
filterChainDefinitionMap.put("/anonymous/**", "anon");
//分享相关接口
filterChainDefinitionMap.put("/api/share/doc/view/**", "anon");
filterChainDefinitionMap.put("/system/theme", "anon");
filterChainDefinitionMap.put("/system/parameter/save/base-url/**", "anon");

View File

@ -0,0 +1,10 @@
package io.metersphere.api.constants;
/**
* @author: LAN
* @date: 2023/12/27 15:32
* @version: 1.0
*/
public enum ShareInfoType {
Single, Batch
}

View File

@ -187,7 +187,7 @@ public class ApiDefinitionController {
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_READ)
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
public ApiDefinitionDocDTO getDocInfo(@Validated @RequestBody ApiDefinitionDocRequest request) {
return apiDefinitionService.getDocInfo(request, SessionUtils.getUserId());
return apiDefinitionService.getDocInfo(request);
}
}

View File

@ -0,0 +1,46 @@
package io.metersphere.api.controller.definition;
import io.metersphere.api.dto.definition.ApiDefinitionDocDTO;
import io.metersphere.api.dto.definition.ApiDefinitionDocRequest;
import io.metersphere.api.dto.share.ShareInfoDTO;
import io.metersphere.api.service.ApiShareService;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.system.security.CheckOwner;
import io.metersphere.system.utils.SessionUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.bind.annotation.*;
import java.util.Objects;
/**
* @author: LAN
* @date: 2023/12/27 14:30
* @version: 1.0
*/
@RestController
@RequestMapping(value = "/api/share")
@Tag(name = "接口测试-接口管理-接口分享")
public class ApiShareController {
@Resource
private ApiShareService apiShareService;
@PostMapping("/doc/gen")
@Operation(summary = "接口测试-接口管理-接口文档分享")
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_READ)
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
public ShareInfoDTO genApiDocShareInfo(@RequestBody ApiDefinitionDocRequest request) {
return apiShareService.genApiDocShareInfo(request, Objects.requireNonNull(SessionUtils.getUser()));
}
@GetMapping("/doc/view/{shareId}")
@Operation(summary = "接口测试-接口管理-接口文档分享查看")
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_READ)
@CheckOwner(resourceId = "#shareId", resourceType = "share_info")
public ApiDefinitionDocDTO shareDocView(@PathVariable String shareId) {
return apiShareService.shareDocView(shareId);
}
}

View File

@ -0,0 +1,14 @@
package io.metersphere.api.dto.share;
import lombok.Data;
/**
* @author: LAN
* @date: 2023/12/27 14:43
* @version: 1.0
*/
@Data
public class ShareInfoDTO {
private String id;
private String shareUrl;
}

View File

@ -0,0 +1,29 @@
package io.metersphere.api.dto.share.request;
import io.metersphere.api.dto.definition.ApiDefinitionDocRequest;
import io.metersphere.sdk.domain.ShareInfo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.Data;
/**
* @author: LAN
* @date: 2023/12/27 14:46
* @version: 1.0
*/
@Data
public class ApiDocShareRequest extends ShareInfo {
@Schema(description = "接口pk")
@Size(min = 1, max = 50, message = "{api_definition.id.length_range}")
private String apiId;
@Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{api_definition.project_id.not_blank}")
@Size(min = 1, max = 50, message = "{api_definition.project_id.length_range}")
private String projectId;
@Schema(description = "接口文档分享选择")
private ApiDefinitionDocRequest selectRequest;
}

View File

@ -0,0 +1,11 @@
package io.metersphere.api.mapper;
import io.metersphere.sdk.domain.ShareInfo;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface ExtShareInfoMapper {
List<ShareInfo> selectByShareTypeAndShareApiIdWithBLOBs(@Param("shareType") String shareType, @Param("customData") byte[] customData, @Param("lang") String lang);
}

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="io.metersphere.api.mapper.ExtShareInfoMapper">
<select id="selectByShareTypeAndShareApiIdWithBLOBs" resultType="io.metersphere.sdk.domain.ShareInfo">
SELECT id,share_type,custom_data FROM share_info
<where>
share_type = #{shareType}
<if test="customData != null and customData != ''">
AND custom_data = #{customData}
</if>
<if test="lang != null and lang != ''">
AND lang = #{lang}
</if>
</where>
</select>
</mapper>

View File

@ -0,0 +1,117 @@
package io.metersphere.api.service;
import io.metersphere.api.constants.ApiDefinitionDocType;
import io.metersphere.api.constants.ShareInfoType;
import io.metersphere.api.dto.definition.ApiDefinitionDocDTO;
import io.metersphere.api.dto.definition.ApiDefinitionDocRequest;
import io.metersphere.api.dto.share.ShareInfoDTO;
import io.metersphere.api.mapper.ExtShareInfoMapper;
import io.metersphere.api.service.definition.ApiDefinitionService;
import io.metersphere.api.utils.ApiDataUtils;
import io.metersphere.sdk.domain.ShareInfo;
import io.metersphere.sdk.mapper.ShareInfoMapper;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.dto.sdk.SessionUser;
import jakarta.annotation.Resource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
/**
* @author: LAN
* @date: 2023/12/27 14:47
* @version: 1.0
*/
@Service
public class ApiShareService {
@Resource
ShareInfoMapper shareInfoMapper;
@Resource
ExtShareInfoMapper extShareInfoMapper;
@Resource
ApiDefinitionService apiDefinitionService;
/**
* 生成 api 接口文档分享信息
* 根据要分享的类型来进行完全匹配搜索
* 搜索的到就返回那条数据搜索不到就新增一条信息
*/
public ShareInfoDTO genApiDocShareInfo(ApiDefinitionDocRequest request, SessionUser user) {
ShareInfo shareInfoRequest = new ShareInfo();
String customData = genCustomData(request, shareInfoRequest);
String lang = user.getLanguage() == null ? LocaleContextHolder.getLocale().toString() : user.getLanguage();
Optional.ofNullable(customData)
.ifPresent(data -> {
BeanUtils.copyBean(shareInfoRequest, request);
shareInfoRequest.setCreateUser(user.getId());
shareInfoRequest.setLang(lang);
shareInfoRequest.setCustomData(data.getBytes());
});
ShareInfo shareInfo = Optional.ofNullable(customData)
.map(data -> genShareInfo(shareInfoRequest))
.orElse(new ShareInfo());
return conversionShareInfoToDTO(shareInfo);
}
private String genCustomData(ApiDefinitionDocRequest request, ShareInfo shareInfoRequest) {
String customData = null;
if (ApiDefinitionDocType.ALL.name().equals(request.getType()) || ApiDefinitionDocType.MODULE.name().equals(request.getType())) {
customData = JSON.toJSONString(request);
shareInfoRequest.setShareType(ShareInfoType.Batch.name());
} else if (ApiDefinitionDocType.API.name().equals(request.getType())) {
apiDefinitionService.checkApiDefinition(request.getApiId());
customData = JSON.toJSONString(request);
shareInfoRequest.setShareType(ShareInfoType.Single.name());
}
return customData;
}
/**
* 生成分享连接
* 如果该数据有连接则返回已有的连接不做有效期判断, 反之创建链接
*
* @param request 分享请求内容
* @return 分享数据
*/
public ShareInfo genShareInfo(ShareInfo request) {
List<ShareInfo> shareInfos = extShareInfoMapper.selectByShareTypeAndShareApiIdWithBLOBs(request.getShareType(), request.getCustomData(), request.getLang());
return shareInfos.isEmpty() ? createShareInfo(request) : shareInfos.get(0);
}
public ShareInfo createShareInfo(ShareInfo shareInfo) {
long createTime = System.currentTimeMillis();
shareInfo.setId(UUID.randomUUID().toString());
shareInfo.setCreateTime(createTime);
shareInfo.setUpdateTime(createTime);
shareInfoMapper.insert(shareInfo);
return shareInfo;
}
public ShareInfoDTO conversionShareInfoToDTO(ShareInfo shareInfo) {
ShareInfoDTO returnDTO = new ShareInfoDTO();
if (null != shareInfo.getCustomData()) {
String url = "?shareId=" + shareInfo.getId();
returnDTO.setId(shareInfo.getId());
returnDTO.setShareUrl(url);
}
return returnDTO;
}
public ApiDefinitionDocDTO shareDocView(String shareId) {
ShareInfo shareInfo = shareInfoMapper.selectByPrimaryKey(shareId);
ApiDefinitionDocRequest apiDefinitionDocRequest = ApiDataUtils.parseObject(new String(shareInfo.getCustomData()), ApiDefinitionDocRequest.class);
return apiDefinitionService.getDocInfo(apiDefinitionDocRequest);
}
}

View File

@ -2,10 +2,7 @@ package io.metersphere.api.service.definition;
import io.metersphere.api.constants.ApiResourceType;
import io.metersphere.api.controller.result.ApiResultCode;
import io.metersphere.api.domain.ApiDefinition;
import io.metersphere.api.domain.ApiDefinitionMock;
import io.metersphere.api.domain.ApiDefinitionMockConfig;
import io.metersphere.api.domain.ApiDefinitionMockExample;
import io.metersphere.api.domain.*;
import io.metersphere.api.dto.debug.ApiFileResourceUpdateRequest;
import io.metersphere.api.dto.definition.ApiDefinitionMockDTO;
import io.metersphere.api.dto.definition.HttpResponse;
@ -198,7 +195,7 @@ public class ApiDefinitionMockService {
public void delete(ApiDefinitionMockRequest request, String userId) {
checkApiDefinitionMock(request.getId());
String apiDefinitionMockDir = DefaultRepositoryDir.getApiDefinitionDir(request.getProjectId(), request.getId());
apiFileResourceService.deleteByResourceId(apiDefinitionMockDir, request.getId(), request.getProjectId(), userId, OperationLogModule.API_DEFINITION);
apiFileResourceService.deleteByResourceId(apiDefinitionMockDir, request.getId(), request.getProjectId(), userId, OperationLogModule.API_DEFINITION_MOCK);
apiDefinitionMockConfigMapper.deleteByPrimaryKey(request.getId());
apiDefinitionMockMapper.deleteByPrimaryKey(request.getId());
}
@ -251,4 +248,26 @@ public class ApiDefinitionMockService {
public String uploadTempFile(MultipartFile file) {
return apiFileResourceService.uploadTempFile(file);
}
public void deleteByApiIds(List<String> apiIds, String userId) {
ApiDefinitionMockExample apiDefinitionMockExample = new ApiDefinitionMockExample();
apiDefinitionMockExample.createCriteria().andApiDefinitionIdIn(apiIds);
List<ApiDefinitionMock> apiDefinitionMocks = apiDefinitionMockMapper.selectByExample(apiDefinitionMockExample);
if(!apiDefinitionMocks.isEmpty()){
apiDefinitionMocks.forEach(item -> {
String apiDefinitionMockDir = DefaultRepositoryDir.getApiDefinitionDir(item.getProjectId(), item.getId());
apiFileResourceService.deleteByResourceId(apiDefinitionMockDir, item.getId(), item.getProjectId(), userId, OperationLogModule.API_DEFINITION_MOCK);
});
List<String> mockIds = apiDefinitionMocks.stream().map(ApiDefinitionMock::getId).toList();
ApiDefinitionMockConfigExample apiDefinitionMockConfigExample = new ApiDefinitionMockConfigExample();
apiDefinitionMockConfigExample.createCriteria().andIdIn(mockIds);
apiDefinitionMockConfigMapper.deleteByExample(apiDefinitionMockConfigExample);
apiDefinitionMockMapper.deleteByExample(apiDefinitionMockExample);
}
}
}

View File

@ -94,6 +94,9 @@ public class ApiDefinitionService {
@Resource
private ApiDefinitionLogService apiDefinitionLogService;
@Resource
private ApiDefinitionMockService apiDefinitionMockService;
public List<ApiDefinitionDTO> getApiDefinitionPage(ApiDefinitionPageRequest request, String userId){
CustomFieldUtils.setBaseQueryRequestCustomMultipleFields(request, userId);
List<ApiDefinitionDTO> list = extApiDefinitionMapper.list(request);
@ -446,7 +449,7 @@ public class ApiDefinitionService {
*
* @param apiId 接口id
*/
private ApiDefinition checkApiDefinition(String apiId) {
public ApiDefinition checkApiDefinition(String apiId) {
ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey(apiId);
if (apiDefinition == null) {
throw new MSException(ApiResultCode.API_DEFINITION_NOT_EXIST);
@ -777,8 +780,9 @@ public class ApiDefinitionService {
List<String> caseIds = caseLists.stream().map(ApiTestCase::getId).distinct().toList();
// case 批量删除回收站
apiTestCaseService.deleteResourceByIds(caseIds, projectId, userId);
}
// 删除 mock
apiDefinitionMockService.deleteByApiIds(apiIds, userId);
}
// 获取批量操作选中的ID
@ -821,7 +825,7 @@ public class ApiDefinitionService {
apiDefinitionDTO.setCustomFields(customFieldMap.get(id));
}
public ApiDefinitionDocDTO getDocInfo(ApiDefinitionDocRequest request, String userId) {
public ApiDefinitionDocDTO getDocInfo(ApiDefinitionDocRequest request) {
ApiDefinitionDocDTO apiDefinitionDocDTO = new ApiDefinitionDocDTO();
apiDefinitionDocDTO.setType(request.getType());
// 下载所有/一个模块接口文档时不做分页数据量大的时候会不会有性能问题单独做接口
@ -830,20 +834,21 @@ public class ApiDefinitionService {
if (!list.isEmpty()) {
ApiDefinitionDTO first = list.get(0);
apiDefinitionLogService.handleBlob(first.getId(), first);
if(ApiDefinitionDocType.ALL.name().equals(request.getType())){
apiDefinitionDocDTO.setDocTitle(Translator.get(ALL_API));
String docTitle;
if (ApiDefinitionDocType.ALL.name().equals(request.getType())) {
docTitle = Translator.get(ALL_API);
} else {
ApiDefinitionModule apiDefinitionModule = apiDefinitionModuleMapper.selectByPrimaryKey(first.getModuleId());
if (apiDefinitionModule != null) {
apiDefinitionDocDTO.setDocTitle(apiDefinitionModule.getName());
} else {
apiDefinitionDocDTO.setDocTitle(Translator.get(UNPLANNED_API));
}
docTitle = (apiDefinitionModule != null) ? apiDefinitionModule.getName() : Translator.get(UNPLANNED_API);
}
apiDefinitionDocDTO.setDocTitle(docTitle);
apiDefinitionDocDTO.setDocInfo(first);
}
} else if (ApiDefinitionDocType.API.name().equals(request.getType())) {
ApiDefinitionDTO apiDefinitionDTO = get(request.getApiId(), userId);
ApiDefinition apiDefinition = checkApiDefinition(request.getApiId());
ApiDefinitionDTO apiDefinitionDTO = new ApiDefinitionDTO();
BeanUtils.copyBean(apiDefinitionDTO, apiDefinition);
apiDefinitionLogService.handleBlob(apiDefinition.getId(), apiDefinitionDTO);
apiDefinitionDocDTO.setDocTitle(apiDefinitionDTO.getName());
apiDefinitionDocDTO.setDocInfo(apiDefinitionDTO);
}

View File

@ -0,0 +1,159 @@
package io.metersphere.api.controller;
import io.metersphere.api.constants.ApiDefinitionDocType;
import io.metersphere.api.constants.ShareInfoType;
import io.metersphere.api.controller.result.ApiResultCode;
import io.metersphere.api.domain.ApiDefinition;
import io.metersphere.api.domain.ApiDefinitionBlob;
import io.metersphere.api.dto.definition.ApiDefinitionDTO;
import io.metersphere.api.dto.definition.ApiDefinitionDocDTO;
import io.metersphere.api.dto.definition.ApiDefinitionDocRequest;
import io.metersphere.api.dto.definition.HttpResponse;
import io.metersphere.api.dto.request.http.MsHTTPElement;
import io.metersphere.api.dto.share.ShareInfoDTO;
import io.metersphere.api.mapper.ApiDefinitionBlobMapper;
import io.metersphere.api.mapper.ApiDefinitionMapper;
import io.metersphere.api.mapper.ExtApiDefinitionMapper;
import io.metersphere.api.mapper.ExtShareInfoMapper;
import io.metersphere.api.utils.ApiDataUtils;
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.domain.ShareInfo;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.mapper.ShareInfoMapper;
import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.base.BaseTest;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.jdbc.SqlConfig;
import org.springframework.test.web.servlet.MvcResult;
import java.util.List;
@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@AutoConfigureMockMvc
public class ApiShareControllerTests extends BaseTest {
private static final String BASE_PATH = "/api/share/";
private static final String SHARE_DOC = BASE_PATH + "/doc/gen";
private static final String SHARE_VIEW = BASE_PATH + "/doc/view/";
private static final String ALL_API = "api_definition_module.api.all";
@Resource
private ApiDefinitionMapper apiDefinitionMapper;
@Resource
private ApiDefinitionBlobMapper apiDefinitionBlobMapper;
@Resource
private ExtApiDefinitionMapper extApiDefinitionMapper;
@Resource
private ExtShareInfoMapper extShareInfoMapper;
@Resource
private ShareInfoMapper shareInfoMapper;
@Test
@Order(1)
@Sql(scripts = {"/dml/init_api_definition.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED))
public void testShareDoc() throws Exception {
ApiDefinitionDocRequest request = new ApiDefinitionDocRequest();
ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey("1001");
request.setApiId(apiDefinition.getId());
request.setProjectId(DEFAULT_PROJECT_ID);
request.setType(ApiDefinitionDocType.API.name());
// @@请求成功
this.requestPostWithOkAndReturn(SHARE_DOC, request);
MvcResult mvcResult = this.requestPostWithOkAndReturn(SHARE_DOC, request);
ApiDataUtils.setResolver(MsHTTPElement.class);
ShareInfoDTO shareInfoDTO = ApiDataUtils.parseObject(JSON.toJSONString(parseResponse(mvcResult).get("data")), ShareInfoDTO.class);
// 校验数据是否正确
List<ShareInfo> shareInfos = extShareInfoMapper.selectByShareTypeAndShareApiIdWithBLOBs(ShareInfoType.Single.name(), JSON.toJSONString(request).getBytes(), "zh_CN");
Assertions.assertNotNull(shareInfos);
Assertions.assertEquals(1, shareInfos.size());
Assertions.assertEquals(shareInfoDTO.getId(), shareInfos.get(0).getId());
Assertions.assertTrue(shareInfoDTO.getShareUrl().contains("?shareId="));
request.setApiId("111");
assertErrorCode(this.requestPost(SHARE_DOC, request), ApiResultCode.API_DEFINITION_NOT_EXIST);
// @@分享模块文档
request.setApiId(null);
request.setProjectId(DEFAULT_PROJECT_ID);
request.setType(ApiDefinitionDocType.MODULE.name());
request.setModuleIds(List.of("10001"));
MvcResult mvcResultModule = this.requestPostWithOkAndReturn(SHARE_DOC, request);
ApiDataUtils.setResolver(MsHTTPElement.class);
ShareInfoDTO shareInfoDTOModule = ApiDataUtils.parseObject(JSON.toJSONString(parseResponse(mvcResultModule).get("data")), ShareInfoDTO.class);
// 校验数据是否正确
List<ShareInfo> shareInfosModule = extShareInfoMapper.selectByShareTypeAndShareApiIdWithBLOBs(ShareInfoType.Batch.name(), JSON.toJSONString(request).getBytes(), "zh_CN");
Assertions.assertNotNull(shareInfosModule);
Assertions.assertEquals(1, shareInfosModule.size());
Assertions.assertEquals(shareInfoDTOModule.getId(), shareInfosModule.get(0).getId());
Assertions.assertTrue(shareInfoDTOModule.getShareUrl().contains("?shareId="));
// @@分享全部文档
request.setApiId(null);
request.setModuleIds(null);
request.setProjectId(DEFAULT_PROJECT_ID);
request.setType(ApiDefinitionDocType.ALL.name());
MvcResult mvcResultAll = this.requestPostWithOkAndReturn(SHARE_DOC, request);
ApiDataUtils.setResolver(MsHTTPElement.class);
ShareInfoDTO allShareInfoDTO = ApiDataUtils.parseObject(JSON.toJSONString(parseResponse(mvcResultAll).get("data")), ShareInfoDTO.class);
// 校验数据是否正确
List<ShareInfo> allShareInfos = extShareInfoMapper.selectByShareTypeAndShareApiIdWithBLOBs(ShareInfoType.Batch.name(), JSON.toJSONString(request).getBytes(), "zh_CN");
Assertions.assertNotNull(allShareInfos);
Assertions.assertEquals(1, allShareInfos.size());
Assertions.assertEquals(allShareInfoDTO.getId(), allShareInfos.get(0).getId());
Assertions.assertTrue(allShareInfoDTO.getShareUrl().contains("?shareId="));
assertTestShareView(allShareInfoDTO.getId());
// @@校验权限
requestPostPermissionTest(PermissionConstants.PROJECT_API_DEFINITION_READ, SHARE_DOC, request);
}
public void assertTestShareView(String shareId) throws Exception {
// @@请求成功
ShareInfo shareInfo = shareInfoMapper.selectByPrimaryKey(shareId);
ApiDefinitionDocRequest apiDefinitionDocRequest = ApiDataUtils.parseObject(new String(shareInfo.getCustomData()), ApiDefinitionDocRequest.class);
MvcResult mvcResultAll = this.requestGetWithOkAndReturn(SHARE_VIEW + shareId);
ApiDataUtils.setResolver(MsHTTPElement.class);
ApiDefinitionDocDTO allApiDefinitionDocDTO = ApiDataUtils.parseObject(JSON.toJSONString(parseResponse(mvcResultAll).get("data")), ApiDefinitionDocDTO.class);
// 校验数据是否正确
ApiDefinitionDocDTO copyAllApiDefinitionDocDTO = new ApiDefinitionDocDTO();
List<ApiDefinitionDTO> allList = extApiDefinitionMapper.listDoc(apiDefinitionDocRequest);
if(null != allList){
ApiDefinitionDTO info = allList.stream().findFirst().orElseThrow(() -> new MSException(ApiResultCode.API_DEFINITION_NOT_EXIST));
ApiDefinitionBlob allApiDefinitionBlob = apiDefinitionBlobMapper.selectByPrimaryKey(info.getId());
if(allApiDefinitionBlob != null){
info.setRequest(ApiDataUtils.parseObject(new String(allApiDefinitionBlob.getRequest()), AbstractMsTestElement.class));
info.setResponse(ApiDataUtils.parseArray(new String(allApiDefinitionBlob.getResponse()), HttpResponse.class));
}
if(StringUtils.isBlank(copyAllApiDefinitionDocDTO.getDocTitle())){
copyAllApiDefinitionDocDTO.setDocTitle(Translator.get(ALL_API));
}
copyAllApiDefinitionDocDTO.setType(ApiDefinitionDocType.ALL.name());
copyAllApiDefinitionDocDTO.setDocInfo(info);
}
Assertions.assertEquals(allApiDefinitionDocDTO.getType(), copyAllApiDefinitionDocDTO.getType());
Assertions.assertEquals(allApiDefinitionDocDTO.getDocTitle(), copyAllApiDefinitionDocDTO.getDocTitle());
Assertions.assertEquals(allApiDefinitionDocDTO.getDocInfo().getId(), copyAllApiDefinitionDocDTO.getDocInfo().getId());
// @@校验权限
requestGetPermissionTest(PermissionConstants.PROJECT_API_DEFINITION_READ, SHARE_VIEW + shareId);
}
}

View File

@ -57,3 +57,21 @@ DELETE FROM `template` WHERE `id` in ('api-template-id', 'default-api-template-i
INSERT INTO template (id, name, remark, internal, update_time, create_time, create_user, scope_type, scope_id, enable_third_part, scene) VALUES
('api-template-id', 'api-template', '', 0, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'PROJECT', '100001100001', 0, 'API'),
('default-api-template-id', 'api-default-template', '', 0, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'PROJECT', '100001100001', 0, 'API');
DELETE FROM `api_definition_mock` WHERE `id` in ('mock_1', 'mock_2', 'mock_3', 'mock_4','mock_5');
INSERT INTO `api_definition_mock` VALUES
('mock_1', 1641120000000, 1641120000000, 'user1', 'Mock 1', '[\"tag1\",\"tag2\"]', 1, 'EXPECT001', '100001100001', '1001'),
('mock_2', 1641121000000, 1641121000000, 'user2', 'Mock 2', '[\"tag2\",\"tag3\"]', 1, 'EXPECT002', '100001100001', '1002'),
('mock_3', 1641122000000, 1641122000000, 'user3', 'Mock 3', '[\"tag3\",\"tag4\"]', 1, 'EXPECT003', '100001100001', '1003'),
('mock_4', 1641123000000, 1641123000000, 'user1', 'Mock 4', '[\"tag4\",\"tag5\"]', 1, 'EXPECT004', '100001100001', '1005'),
('mock_5', 1641124000000, 1641124000000, 'user2', 'Mock 5', '[\"tag5\",\"tag1\"]', 1, 'EXPECT005', '100001100001', '1005');
DELETE FROM `api_definition_mock_config` WHERE `id` in ('mock_1', 'mock_2', 'mock_3', 'mock_4','mock_5');
INSERT INTO `api_definition_mock_config` VALUES
('mock_1', '{"type": "exact", "value": "request_value"}', '{"status": 200, "body": {"message": "Mock Response 1"}}'),
('mock_2', '{"type": "regex", "value": "\\d{3}"}', '{"status": 404, "body": {"error": "Not Found"}}'),
('mock_3', '{"type": "contains", "value": "partial_value"}', '{"status": 500, "body": {"error": "Internal Server Error"}}'),
('mock_4', '{"type": "exact", "value": "another_exact_value"}', '{"status": 200, "body": {"data": "Another Mock Response"}}'),
('mock_5', '{"type": "jsonpath", "value": "$.items[0].name"}', '{"status": 200, "body": {"items": [{"name": "Item 1"}]}}');

View File

@ -18,6 +18,9 @@ public class ApiTestInterceptor {
configList.add(new MybatisInterceptorConfig(ApiDefinitionBlob.class, "request", CompressUtils.class, "zip", "unzip"));
configList.add(new MybatisInterceptorConfig(ApiDefinitionBlob.class, "response", CompressUtils.class, "zip", "unzip"));
configList.add(new MybatisInterceptorConfig(ApiDefinitionBlob.class, "remark", CompressUtils.class, "zip", "unzip"));
// ApiDefinitionMockConfig
configList.add(new MybatisInterceptorConfig(ApiDefinitionMockConfig.class, "matching", CompressUtils.class, "zip", "unzip"));
configList.add(new MybatisInterceptorConfig(ApiDefinitionMockConfig.class, "response", CompressUtils.class, "zip", "unzip"));
// ApiTestCaseBlob
configList.add(new MybatisInterceptorConfig(ApiTestCaseBlob.class, "request", CompressUtils.class, "zip", "unzip"));
// ApiReportBlob

View File

@ -1,6 +1,7 @@
package io.metersphere.system.config.interceptor;
import io.metersphere.sdk.domain.OperationLogBlob;
import io.metersphere.sdk.domain.ShareInfo;
import io.metersphere.sdk.util.CompressUtils;
import io.metersphere.system.utils.MybatisInterceptorConfig;
import org.springframework.context.annotation.Bean;
@ -17,6 +18,8 @@ public class SdkInterceptor {
configList.add(new MybatisInterceptorConfig(OperationLogBlob.class, "originalValue", CompressUtils.class, "zip", "unzip"));
configList.add(new MybatisInterceptorConfig(OperationLogBlob.class, "modifiedValue", CompressUtils.class, "zip", "unzip"));
// ShareInfo
configList.add(new MybatisInterceptorConfig(ShareInfo.class, "customData", CompressUtils.class, "zipString", "unzipString"));
return configList;
}