feat(接口测试): MockServer功能开发
This commit is contained in:
parent
c95a5c047c
commit
9372b82e98
|
@ -27,6 +27,9 @@ public class FilterChainUtils {
|
|||
filterChainDefinitionMap.put("/authsource/list/allenable", "anon");
|
||||
filterChainDefinitionMap.put("/sso/callback/**", "anon");
|
||||
filterChainDefinitionMap.put("/license/validate", "anon");
|
||||
//mock-server
|
||||
filterChainDefinitionMap.put("/mock-server/**", "anon");
|
||||
|
||||
//功能用例副文本访问
|
||||
filterChainDefinitionMap.put("/attachment/download/file/**", "anon");
|
||||
//用例评审副文本访问
|
||||
|
|
|
@ -4,6 +4,7 @@ package io.metersphere.sdk.util;
|
|||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dom4j.Document;
|
||||
import org.dom4j.DocumentException;
|
||||
import org.dom4j.Element;
|
||||
import org.dom4j.Node;
|
||||
import org.dom4j.io.OutputFormat;
|
||||
import org.dom4j.io.SAXReader;
|
||||
|
@ -11,10 +12,15 @@ import org.dom4j.io.XMLWriter;
|
|||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.XMLFilterImpl;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class XMLUtils {
|
||||
public static final boolean IS_TRANS = false;
|
||||
|
@ -26,7 +32,7 @@ public class XMLUtils {
|
|||
reader.setFeature("http://xml.org/sax/features/external-general-entities", false);
|
||||
reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
|
||||
reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
|
||||
}catch (Exception e){
|
||||
} catch (Exception e) {
|
||||
LogUtils.error(e);
|
||||
}
|
||||
if (!IS_TRANS) {
|
||||
|
@ -100,4 +106,40 @@ public class XMLUtils {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Document stringToDocument(String xml) throws Exception {
|
||||
return getDocument(new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8.name())));
|
||||
}
|
||||
|
||||
public static Map<String, Object> xmlStringToJson(String xml) {
|
||||
try {
|
||||
return elementToMap(stringToDocument(xml).getRootElement());
|
||||
} catch (Exception e) {
|
||||
LogUtils.error(e);
|
||||
}
|
||||
return new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
private static Map<String, Object> elementToMap(Element node) {
|
||||
LinkedHashMap<String, Object> result = new LinkedHashMap<>();
|
||||
|
||||
List<Element> listElement = node.elements();// 所有一级子节点的list
|
||||
if (!listElement.isEmpty()) {
|
||||
List<Map<String, Object>> list = new ArrayList<>();
|
||||
for (Element e : listElement) {// 遍历所有一级子节点
|
||||
Map<String, Object> jsonObject = elementToMap(e);
|
||||
list.add(jsonObject);
|
||||
}
|
||||
if (list.size() == 1) {
|
||||
result.put(node.getName(), list.get(0));
|
||||
} else {
|
||||
result.put(node.getName(), list);
|
||||
}
|
||||
} else {
|
||||
if (!StringUtils.isAllBlank(node.getName(), node.getText())) {
|
||||
result.put(node.getName(), node.getText());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,5 +4,6 @@ public enum ApiResource {
|
|||
PROJECT,
|
||||
API_DEFINITION,
|
||||
API_TEST_CASE,
|
||||
API_SCENARIO
|
||||
API_SCENARIO,
|
||||
API_DEFINITION_MOCK,
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package io.metersphere.api.constants.mockserver;
|
||||
|
||||
// mock匹配规则
|
||||
public enum ParamConditionEnums {
|
||||
EQUALS, NOT_EQUALS, CONTAINS, LENGTH_EQUALS, LENGTH_NOT_EQUALS, LENGTH_LARGE, LENGTH_SHOT, REGULAR_MATCH
|
||||
}
|
|
@ -2,12 +2,15 @@ package io.metersphere.api.controller.definition;
|
|||
|
||||
import com.github.pagehelper.Page;
|
||||
import com.github.pagehelper.page.PageMethod;
|
||||
import io.metersphere.api.constants.ApiResource;
|
||||
import io.metersphere.api.domain.ApiDefinitionMock;
|
||||
import io.metersphere.api.dto.definition.ApiDefinitionMockDTO;
|
||||
import io.metersphere.api.dto.definition.request.ApiDefinitionMockAddRequest;
|
||||
import io.metersphere.api.dto.definition.request.ApiDefinitionMockPageRequest;
|
||||
import io.metersphere.api.dto.definition.request.ApiDefinitionMockRequest;
|
||||
import io.metersphere.api.dto.definition.request.ApiDefinitionMockUpdateRequest;
|
||||
import io.metersphere.api.service.ApiFileResourceService;
|
||||
import io.metersphere.api.service.ApiValidateService;
|
||||
import io.metersphere.api.service.definition.ApiDefinitionMockLogService;
|
||||
import io.metersphere.api.service.definition.ApiDefinitionMockNoticeService;
|
||||
import io.metersphere.api.service.definition.ApiDefinitionMockService;
|
||||
|
@ -43,12 +46,17 @@ public class ApiDefinitionMockController {
|
|||
|
||||
@Resource
|
||||
private ApiDefinitionMockService apiDefinitionMockService;
|
||||
@Resource
|
||||
private ApiFileResourceService apiFileResourceService;
|
||||
@Resource
|
||||
private ApiValidateService apiValidateService;
|
||||
|
||||
@PostMapping("/page")
|
||||
@Operation(summary = "接口测试-接口管理-接口 Mock")
|
||||
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_MOCK_READ)
|
||||
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
|
||||
public Pager<List<ApiDefinitionMockDTO>> getPage(@Validated @RequestBody ApiDefinitionMockPageRequest request) {
|
||||
apiValidateService.validateApiMenuInProject(request.getProjectId(), ApiResource.PROJECT.name());
|
||||
Page<Object> page = PageMethod.startPage(request.getCurrent(), request.getPageSize(),
|
||||
StringUtils.isNotBlank(request.getSortString()) ? request.getSortString() : "create_time desc");
|
||||
return PageUtils.setPageInfo(page, apiDefinitionMockService.getPage(request));
|
||||
|
@ -59,6 +67,7 @@ public class ApiDefinitionMockController {
|
|||
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_MOCK_READ)
|
||||
@CheckOwner(resourceId = "#request.getId()", resourceType = "api_definition_mock")
|
||||
public ApiDefinitionMockDTO detail(@Validated @RequestBody ApiDefinitionMockRequest request) {
|
||||
apiValidateService.validateApiMenuInProject(request.getProjectId(), ApiResource.PROJECT.name());
|
||||
return apiDefinitionMockService.detail(request);
|
||||
}
|
||||
|
||||
|
@ -69,6 +78,7 @@ public class ApiDefinitionMockController {
|
|||
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
|
||||
@SendNotice(taskType = NoticeConstants.TaskType.API_DEFINITION_TASK, event = NoticeConstants.Event.MOCK_CREATE, target = "#targetClass.getApiMockDTO(#request)", targetClass = ApiDefinitionMockNoticeService.class)
|
||||
public ApiDefinitionMock add(@Validated @RequestBody ApiDefinitionMockAddRequest request) {
|
||||
apiValidateService.validateApiMenuInProject(request.getApiDefinitionId(), ApiResource.API_DEFINITION.name());
|
||||
return apiDefinitionMockService.create(request, SessionUtils.getUserId());
|
||||
}
|
||||
|
||||
|
@ -79,6 +89,7 @@ public class ApiDefinitionMockController {
|
|||
@CheckOwner(resourceId = "#request.getId()", resourceType = "api_definition_mock")
|
||||
@SendNotice(taskType = NoticeConstants.TaskType.API_DEFINITION_TASK, event = NoticeConstants.Event.MOCK_UPDATE, target = "#targetClass.getApiMockDTO(#request)", targetClass = ApiDefinitionMockNoticeService.class)
|
||||
public ApiDefinitionMock update(@Validated @RequestBody ApiDefinitionMockUpdateRequest request) {
|
||||
apiValidateService.validateApiMenuInProject(request.getId(), ApiResource.API_DEFINITION_MOCK.name());
|
||||
return apiDefinitionMockService.update(request, SessionUtils.getUserId());
|
||||
}
|
||||
|
||||
|
@ -88,6 +99,7 @@ public class ApiDefinitionMockController {
|
|||
@Log(type = OperationLogType.UPDATE, expression = "#msClass.updateEnableLog(#id)", msClass = ApiDefinitionMockLogService.class)
|
||||
@CheckOwner(resourceId = "#id", resourceType = "api_definition_mock")
|
||||
public void updateEnable(@PathVariable String id) {
|
||||
apiValidateService.validateApiMenuInProject(id, ApiResource.API_DEFINITION_MOCK.name());
|
||||
apiDefinitionMockService.updateEnable(id);
|
||||
}
|
||||
|
||||
|
@ -98,6 +110,7 @@ public class ApiDefinitionMockController {
|
|||
@CheckOwner(resourceId = "#request.getId()", resourceType = "api_definition_mock")
|
||||
@SendNotice(taskType = NoticeConstants.TaskType.API_DEFINITION_TASK, event = NoticeConstants.Event.MOCK_DELETE, target = "#targetClass.getApiMockDTO(#request.id)", targetClass = ApiDefinitionMockNoticeService.class)
|
||||
public void delete(@Validated @RequestBody ApiDefinitionMockRequest request) {
|
||||
apiValidateService.validateApiMenuInProject(request.getId(), ApiResource.API_DEFINITION_MOCK.name());
|
||||
apiDefinitionMockService.delete(request, SessionUtils.getUserId());
|
||||
}
|
||||
|
||||
|
@ -107,6 +120,7 @@ public class ApiDefinitionMockController {
|
|||
@Log(type = OperationLogType.UPDATE, expression = "#msClass.copyLog(#request)", msClass = ApiDefinitionMockLogService.class)
|
||||
@CheckOwner(resourceId = "#request.getId()", resourceType = "api_definition_mock")
|
||||
public ApiDefinitionMock copy(@Validated @RequestBody ApiDefinitionMockRequest request) {
|
||||
apiValidateService.validateApiMenuInProject(request.getId(), ApiResource.API_DEFINITION_MOCK.name());
|
||||
return apiDefinitionMockService.copy(request, SessionUtils.getUserId());
|
||||
}
|
||||
|
||||
|
@ -114,8 +128,6 @@ public class ApiDefinitionMockController {
|
|||
@Operation(summary = "上传接口 Mock 所需的文件资源,并返回文件ID")
|
||||
@RequiresPermissions(logical = Logical.OR, value = {PermissionConstants.PROJECT_API_DEFINITION_MOCK_ADD, PermissionConstants.PROJECT_API_DEFINITION_MOCK_UPDATE})
|
||||
public String uploadTempFile(@RequestParam("file") MultipartFile file) {
|
||||
return apiDefinitionMockService.uploadTempFile(file);
|
||||
return apiFileResourceService.uploadTempFile(file);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
package io.metersphere.api.controller.mockserver;
|
||||
|
||||
import io.metersphere.api.service.mockserver.MockServerService;
|
||||
import io.metersphere.api.utils.MockServerUtils;
|
||||
import io.metersphere.sdk.constants.HttpMethodConstants;
|
||||
import io.metersphere.system.controller.handler.annotation.NoResultHolder;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(value = "/mock-server")
|
||||
@Tag(name = "接口测试-接口管理-接口定义-Mock")
|
||||
public class MockServerController {
|
||||
|
||||
@Resource
|
||||
private MockServerService mockServerService;
|
||||
|
||||
@RequestMapping(value = "/{projectNum}/{apiInfo}/**", method = RequestMethod.OPTIONS)
|
||||
@NoResultHolder
|
||||
public Object optionsRequest(@PathVariable String projectNum, @PathVariable String apiInfo, HttpServletRequest request, HttpServletResponse response) {
|
||||
Map<String, String> requestHeaderMap = MockServerUtils.getHttpRequestHeader(request);
|
||||
return mockServerService.execute(HttpMethodConstants.OPTIONS.name(), requestHeaderMap, projectNum, apiInfo, request, response);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/{projectNum}/{apiInfo}/**")
|
||||
@NoResultHolder
|
||||
public Object mockRequest(@PathVariable String projectNum, @PathVariable String apiInfo, HttpServletRequest request, HttpServletResponse response) {
|
||||
Map<String, String> requestHeaderMap = MockServerUtils.getHttpRequestHeader(request);
|
||||
String method = request.getMethod();
|
||||
return mockServerService.execute(method, requestHeaderMap, projectNum, apiInfo, request, response);
|
||||
}
|
||||
}
|
|
@ -1,13 +1,12 @@
|
|||
package io.metersphere.api.dto.definition;
|
||||
|
||||
import io.metersphere.api.domain.ApiDefinitionMock;
|
||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||
import io.metersphere.api.dto.mockserver.MockMatchRule;
|
||||
import io.metersphere.api.dto.mockserver.MockResponse;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author lan
|
||||
*/
|
||||
|
@ -16,10 +15,10 @@ import java.util.List;
|
|||
public class ApiDefinitionMockDTO extends ApiDefinitionMock {
|
||||
|
||||
@Schema(description = "请求内容")
|
||||
private AbstractMsTestElement matching;
|
||||
private MockMatchRule matching;
|
||||
|
||||
@Schema(description = "响应内容")
|
||||
private List<HttpResponse> response;
|
||||
private MockResponse response;
|
||||
|
||||
@Schema(description = "创建人名称")
|
||||
private String createUserName;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package io.metersphere.api.dto.definition;
|
||||
|
||||
import io.metersphere.api.dto.request.http.Header;
|
||||
import io.metersphere.api.dto.request.http.body.Body;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
|
@ -11,6 +10,7 @@ import java.util.List;
|
|||
|
||||
/**
|
||||
* @author: LAN
|
||||
* @editer: 建国
|
||||
* @date: 2023/11/21 18:12
|
||||
* @version: 1.0
|
||||
*/
|
||||
|
@ -20,30 +20,22 @@ public class HttpResponse implements Serializable {
|
|||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "唯一ID")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "响应码")
|
||||
private String statusCode;
|
||||
|
||||
@Schema(description = "默认响应标识")
|
||||
private boolean defaultFlag;
|
||||
|
||||
@Schema(description = "响应名称")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 请求头
|
||||
*/
|
||||
@Schema(description = "响应请求头")
|
||||
private List<Header> headers;
|
||||
|
||||
/**
|
||||
* 请求体
|
||||
*/
|
||||
@Schema(description = "响应请求体")
|
||||
private Body body;
|
||||
private ResponseBody body;
|
||||
|
||||
/**
|
||||
* 请求方法
|
||||
*/
|
||||
@Schema(description = "响应请求方法")
|
||||
private String statusCode;
|
||||
|
||||
/**
|
||||
* 默认标识
|
||||
*/
|
||||
@Schema(description = "默认响应标识")
|
||||
private Boolean defaultFlag;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
package io.metersphere.api.dto.definition;
|
||||
|
||||
import io.metersphere.api.dto.ApiFile;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ResponseBinaryBody extends ApiFile {
|
||||
private boolean sendAsBody;
|
||||
private String description;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package io.metersphere.api.dto.definition;
|
||||
|
||||
import io.metersphere.api.dto.request.http.body.JsonBody;
|
||||
import io.metersphere.api.dto.request.http.body.RawBody;
|
||||
import io.metersphere.api.dto.request.http.body.XmlBody;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 接口响应体、mock期望响应体中使用到的body
|
||||
*/
|
||||
@Data
|
||||
public class ResponseBody implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@NotBlank
|
||||
@Size(max = 20)
|
||||
private String bodyType;
|
||||
|
||||
@Valid
|
||||
private JsonBody jsonBody;
|
||||
|
||||
@Valid
|
||||
private XmlBody xmlBody;
|
||||
|
||||
@Valid
|
||||
private RawBody rawBody;
|
||||
|
||||
@Valid
|
||||
private ResponseBinaryBody binaryBody;
|
||||
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
package io.metersphere.api.dto.definition.request;
|
||||
|
||||
import io.metersphere.api.dto.mockserver.MockMatchRule;
|
||||
import io.metersphere.api.dto.mockserver.MockResponse;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
@ -32,17 +34,14 @@ public class ApiDefinitionMockAddRequest implements Serializable {
|
|||
|
||||
@Schema(description = "标签")
|
||||
private LinkedHashSet<
|
||||
@NotBlank
|
||||
@Size(min = 1, max = 64, message = "{api_test_case.tag.length_range}")
|
||||
String> tags;
|
||||
|
||||
@Schema(description = "请求内容")
|
||||
@NotBlank
|
||||
private String matching;
|
||||
private MockMatchRule mockMatchRule;
|
||||
|
||||
@Schema(description = "请求内容")
|
||||
@NotBlank
|
||||
private String response;
|
||||
private MockResponse response;
|
||||
|
||||
@Schema(description = "接口fk", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "{api_definition_mock.api_definition_id.not_blank}")
|
||||
|
|
|
@ -26,10 +26,4 @@ public class ApiDefinitionMockRequest implements Serializable {
|
|||
@NotBlank(message = "{api_definition_mock.project_id.not_blank}")
|
||||
@Size(min = 1, max = 50, message = "{api_definition_mock.project_id.length_range}")
|
||||
private String projectId;
|
||||
|
||||
@Schema(description = "接口fk", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "{api_definition_mock.api_definition_id.not_blank}")
|
||||
@Size(min = 1, max = 50, message = "{api_definition_mock.api_definition_id.length_range}")
|
||||
private String apiDefinitionId;
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
package io.metersphere.api.dto.mockserver;
|
||||
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
import io.metersphere.sdk.util.XMLUtils;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
public class BodyParamMatchRole {
|
||||
@Schema(description = "参数类型(kv/json/xml/raw 默认为raw)")
|
||||
private String paramType;
|
||||
@Schema(description = "formData的匹配规则")
|
||||
private keyValueMatchRole formDataMatch;
|
||||
@Schema(description = "文本匹配规则")
|
||||
private String raw;
|
||||
|
||||
public boolean matchXml(Map<String, Object> requestMap) {
|
||||
Map<String, Object> mockMap = XMLUtils.xmlStringToJson(raw);
|
||||
return this.matchMap(mockMap, requestMap);
|
||||
}
|
||||
|
||||
public boolean matchJson(String requestJson) {
|
||||
|
||||
if (StringUtils.startsWith(requestJson, "{") && StringUtils.endsWith(requestJson, "}")) {
|
||||
//入参是Object,如果mock期望设置的不是Object,视为无法匹配
|
||||
if (StringUtils.startsWith(this.raw, "{") && StringUtils.endsWith(this.raw, "}")) {
|
||||
Map<String, Object> mockMap = JSON.parseMap(this.raw);
|
||||
Map<String, Object> requestMap = JSON.parseMap(requestJson);
|
||||
return this.matchObject(mockMap, requestMap);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.startsWith(requestJson, "[") && StringUtils.endsWith(requestJson, "]")) {
|
||||
List<Object> requestList = JSON.parseArray(requestJson, Object.class);
|
||||
if (StringUtils.startsWith(this.raw, "{") && StringUtils.endsWith(this.raw, "}")) {
|
||||
//入参是Array,如果mock期望设置是Object,则入参中的任意一个匹配,视为匹配
|
||||
Map<String, Object> mockMap = JSON.parseMap(this.raw);
|
||||
for (Object requestObj : requestList) {
|
||||
if (this.matchObject(mockMap, requestObj)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else if (StringUtils.startsWith(this.raw, "[") && StringUtils.endsWith(this.raw, "]")) {
|
||||
//入参是Array,如果mock期望设置也是Array,则Mock中的每个数据都匹配才视为匹配
|
||||
List<Object> mockList = JSON.parseArray(requestJson, Object.class);
|
||||
for (Object mockObj : mockList) {
|
||||
boolean match = false;
|
||||
for (int i = 0; i < requestList.size(); i++) {
|
||||
Object requestObj = requestList.get(i);
|
||||
match = this.matchObject(mockObj, requestObj);
|
||||
if (match) {
|
||||
requestList.remove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!match) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean matchMap(Map<String, Object> mockMap, Map<String, Object> requestMap) {
|
||||
for (Map.Entry<String, Object> entry : mockMap.entrySet()) {
|
||||
if (!this.matchObject(entry.getValue(), requestMap.get(entry.getKey()))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean matchObject(Object mockRule, Object requestParam) {
|
||||
if (ObjectUtils.anyNull(mockRule, requestParam)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mockRule instanceof List<?> && requestParam instanceof List<?>) {
|
||||
List<Object> mockList = (List<Object>) mockRule;
|
||||
List<Object> requestList = (List<Object>) requestParam;
|
||||
if (mockList.size() != requestList.size()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < mockList.size(); i++) {
|
||||
if (!this.matchObject(mockList.get(i), requestList.get(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else if (mockRule instanceof Map<?, ?> && requestParam instanceof Map<?, ?>) {
|
||||
Map<String, Object> mockMap = (Map<String, Object>) mockRule;
|
||||
Map<String, Object> requestMap = (Map<String, Object>) requestParam;
|
||||
for (Map.Entry<?, ?> entry : mockMap.entrySet()) {
|
||||
if (!this.matchObject(entry.getValue(), requestMap.get(entry.getKey()))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//既不是list也不是object,直接进行值比对
|
||||
return StringUtils.equals(String.valueOf(mockRule), String.valueOf(requestParam));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package io.metersphere.api.dto.mockserver;
|
||||
|
||||
import io.metersphere.api.dto.request.http.body.Body;
|
||||
import io.metersphere.sdk.util.XMLUtils;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
public class HttpRequestParam {
|
||||
|
||||
private boolean isPost;
|
||||
|
||||
private LinkedHashMap<String, String> restParams;
|
||||
|
||||
//form-data的kv类型参数也存储在queryParamObj中
|
||||
private LinkedHashMap<String, String> queryParamsObj;
|
||||
|
||||
private String paramType;
|
||||
|
||||
//JSONArray 或 JSONObject
|
||||
private String jsonString;
|
||||
|
||||
private Map<String, Object> xmlToJsonParam;
|
||||
|
||||
private String raw;
|
||||
|
||||
public void setXmlParam(String xmlParam) {
|
||||
this.setParamType(Body.BodyType.XML.name());
|
||||
this.setRaw(xmlParam);
|
||||
Map<String, Object> jsonMap = XMLUtils.xmlStringToJson(xmlParam);
|
||||
this.setXmlToJsonParam(jsonMap);
|
||||
}
|
||||
|
||||
public void setJsonParam(String requestPostString) {
|
||||
this.setParamType(Body.BodyType.JSON.name());
|
||||
this.jsonString = requestPostString;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package io.metersphere.api.dto.mockserver;
|
||||
|
||||
import io.metersphere.api.constants.mockserver.ParamConditionEnums;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@Data
|
||||
public class KeyValueInfo {
|
||||
@Schema(description = "Key")
|
||||
private String key;
|
||||
@Schema(description = "Value")
|
||||
private String value;
|
||||
@Schema(description = "条件")
|
||||
private String condition;
|
||||
@Schema(description = "描述")
|
||||
private String description;
|
||||
|
||||
public boolean matchValue(String value) {
|
||||
if (StringUtils.isBlank(this.condition) || StringUtils.equals(this.condition, ParamConditionEnums.EQUALS.name())) {
|
||||
return StringUtils.equals(this.value, value);
|
||||
} else if (StringUtils.equals(this.condition, ParamConditionEnums.NOT_EQUALS.name())) {
|
||||
return !StringUtils.equals(this.value, value);
|
||||
} else if (StringUtils.equals(this.condition, ParamConditionEnums.CONTAINS.name())) {
|
||||
return StringUtils.contains(this.value, value);
|
||||
} else if (StringUtils.equals(this.condition, ParamConditionEnums.LENGTH_EQUALS.name())) {
|
||||
try {
|
||||
int length = Integer.parseInt(value);
|
||||
return this.value.length() == length;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
} else if (StringUtils.equals(this.condition, ParamConditionEnums.LENGTH_NOT_EQUALS.name())) {
|
||||
try {
|
||||
int length = Integer.parseInt(value);
|
||||
return this.value.length() != length;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
} else if (StringUtils.equals(this.condition, ParamConditionEnums.LENGTH_SHOT.name())) {
|
||||
try {
|
||||
int length = Integer.parseInt(value);
|
||||
return this.value.length() < length;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
} else if (StringUtils.equals(this.condition, ParamConditionEnums.LENGTH_LARGE.name())) {
|
||||
try {
|
||||
int length = Integer.parseInt(value);
|
||||
return this.value.length() > length;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
} else if (StringUtils.equals(this.condition, ParamConditionEnums.REGULAR_MATCH.name())) {
|
||||
try {
|
||||
Pattern pattern = Pattern.compile(value);
|
||||
Matcher matcher = pattern.matcher(this.value);
|
||||
boolean isMatch = matcher.matches();
|
||||
return isMatch;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package io.metersphere.api.dto.mockserver;
|
||||
|
||||
import io.metersphere.api.dto.request.http.body.Body;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
//mock匹配规则
|
||||
@Data
|
||||
public class MockMatchRule implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "请求头匹配规则")
|
||||
private keyValueMatchRole header = new keyValueMatchRole();
|
||||
@Schema(description = "query参数匹配规则")
|
||||
private keyValueMatchRole query = new keyValueMatchRole();
|
||||
@Schema(description = "REST参数匹配规则")
|
||||
private keyValueMatchRole rest = new keyValueMatchRole();
|
||||
@Schema(description = "body参数匹配规则")
|
||||
private BodyParamMatchRole body = new BodyParamMatchRole();
|
||||
|
||||
public boolean keyValueMatch(String matchType, Map<String, String> matchParam) {
|
||||
keyValueMatchRole matchRole = null;
|
||||
switch (matchType) {
|
||||
case "header":
|
||||
matchRole = header;
|
||||
break;
|
||||
case "query":
|
||||
matchRole = query;
|
||||
break;
|
||||
case "rest":
|
||||
matchRole = rest;
|
||||
break;
|
||||
case "body":
|
||||
if (body != null) {
|
||||
matchRole = body.getFormDataMatch();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (matchRole == null) {
|
||||
return true;
|
||||
}
|
||||
return matchRole.match(matchParam);
|
||||
}
|
||||
|
||||
public boolean requestParamMatch(HttpRequestParam httpRequestParam) {
|
||||
if (!this.keyValueMatch("rest", httpRequestParam.getRestParams())) {
|
||||
return false;
|
||||
}
|
||||
if (httpRequestParam.isPost()) {
|
||||
if (StringUtils.equalsIgnoreCase(body.getParamType(), Body.BodyType.XML.name())) {
|
||||
return body.matchXml(httpRequestParam.getXmlToJsonParam());
|
||||
} else if (StringUtils.equalsIgnoreCase(body.getParamType(), Body.BodyType.JSON.name())) {
|
||||
return body.matchJson(httpRequestParam.getJsonString());
|
||||
} else if (StringUtils.equalsIgnoreCase(body.getParamType(), Body.BodyType.FORM_DATA.name())) {
|
||||
return this.keyValueMatch("body", httpRequestParam.getQueryParamsObj());
|
||||
} else if (StringUtils.isNotBlank(body.getRaw())) {
|
||||
return StringUtils.contains(body.getRaw(), httpRequestParam.getRaw());
|
||||
}
|
||||
} else {
|
||||
return this.keyValueMatch("query", httpRequestParam.getQueryParamsObj());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package io.metersphere.api.dto.mockserver;
|
||||
|
||||
import io.metersphere.api.dto.definition.ResponseBody;
|
||||
import io.metersphere.api.dto.request.http.Header;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class MockResponse implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "响应码")
|
||||
private int statusCode;
|
||||
|
||||
@Schema(description = "响应请求头")
|
||||
private List<Header> headers;
|
||||
|
||||
@Schema(description = "是否使用api响应体")
|
||||
private boolean useApiResponse;
|
||||
|
||||
@Schema(description = "接口响应ID(useApiResponse为true时使用)")
|
||||
private String apiResponseId;
|
||||
|
||||
@Schema(description = "响应请求体")
|
||||
private ResponseBody body;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package io.metersphere.api.dto.mockserver;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
public class keyValueMatchRole {
|
||||
@Schema(description = "是否是全部匹配 (false为任意匹配)")
|
||||
private boolean isMatchAll;
|
||||
@Schema(description = "匹配规则")
|
||||
private List<KeyValueInfo> matchRules;
|
||||
|
||||
public boolean match(Map<String, String> matchParam) {
|
||||
if (MapUtils.isEmpty(matchParam)) {
|
||||
return true;
|
||||
}
|
||||
if (isMatchAll) {
|
||||
for (KeyValueInfo matchRule : matchRules) {
|
||||
if (!matchRule.matchValue(matchParam.get(matchRule.getKey()))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
for (KeyValueInfo matchRule : matchRules) {
|
||||
if (matchRule.matchValue(matchParam.get(matchRule.getKey()))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -64,4 +64,6 @@ public interface ExtApiDefinitionMapper {
|
|||
Long getLastPos(@Param("projectId") String projectId, @Param("basePos") Long basePos);
|
||||
|
||||
List<ApiResourceModuleInfo> getModuleInfoByIds(@Param("ids") List<String> ids);
|
||||
|
||||
ApiDefinition selectByProjectNumAndApiNum(@Param("projectNum") String projectNum, @Param("apiNum") String apiNum);
|
||||
}
|
||||
|
|
|
@ -550,4 +550,14 @@
|
|||
#{id}
|
||||
</foreach>
|
||||
</select>
|
||||
<select id="selectByProjectNumAndApiNum" resultType="io.metersphere.api.domain.ApiDefinition">
|
||||
select *
|
||||
from api_definition
|
||||
where api_definition.num = #{apiNum}
|
||||
AND project_id IN (SELECT id
|
||||
FROM project
|
||||
WHERE num = #{projectNum})
|
||||
AND latest = true
|
||||
limit 1
|
||||
</select>
|
||||
</mapper>
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package io.metersphere.api.parser.api;
|
||||
|
||||
import io.metersphere.api.constants.ApiConstants;
|
||||
import io.metersphere.api.dto.definition.HttpResponse;
|
||||
import io.metersphere.api.dto.converter.ApiDefinitionImport;
|
||||
import io.metersphere.api.dto.converter.ApiDefinitionImportDetail;
|
||||
import io.metersphere.api.dto.definition.HttpResponse;
|
||||
import io.metersphere.api.dto.definition.ResponseBody;
|
||||
import io.metersphere.api.dto.request.ImportRequest;
|
||||
import io.metersphere.api.dto.request.http.*;
|
||||
import io.metersphere.api.dto.request.http.auth.NoAuth;
|
||||
|
@ -184,14 +185,13 @@ public class Swagger3Parser<T> implements ImportParser<ApiDefinitionImport> {
|
|||
body.setWwwFormBody(wwwFormBody);
|
||||
}
|
||||
|
||||
|
||||
private void parseResponse(ApiResponses responseBody, List<HttpResponse> response) {
|
||||
if (responseBody != null) {
|
||||
responseBody.forEach((key, value) -> {
|
||||
HttpResponse httpResponse = new HttpResponse();
|
||||
//TODO headers
|
||||
httpResponse.setStatusCode(key);
|
||||
Body body = new Body();
|
||||
ResponseBody body = new ResponseBody();
|
||||
Map<String, io.swagger.v3.oas.models.headers.Header> headers = value.getHeaders();
|
||||
if (MapUtils.isNotEmpty(headers)) {
|
||||
List<Header> headerList = new ArrayList<>();
|
||||
|
@ -218,6 +218,49 @@ public class Swagger3Parser<T> implements ImportParser<ApiDefinitionImport> {
|
|||
|
||||
}
|
||||
|
||||
private void setBodyData(String k, io.swagger.v3.oas.models.media.MediaType value, ResponseBody body) {
|
||||
//TODO body 默认如果json格式
|
||||
JsonSchemaItem jsonSchemaItem = parseSchema(value.getSchema());
|
||||
switch (k) {
|
||||
case MediaType.APPLICATION_JSON_VALUE, MediaType.ALL_VALUE -> {
|
||||
body.setBodyType(Body.BodyType.JSON.name());
|
||||
JsonBody jsonBody = new JsonBody();
|
||||
jsonBody.setJsonSchema(jsonSchemaItem);
|
||||
jsonBody.setEnableJsonSchema(true);
|
||||
if (ObjectUtils.isNotEmpty(value.getExample())) {
|
||||
jsonBody.setJsonValue(ApiDataUtils.toJSONString(value.getExample()));
|
||||
}
|
||||
body.setJsonBody(jsonBody);
|
||||
}
|
||||
case MediaType.APPLICATION_XML_VALUE -> {
|
||||
if (StringUtils.isBlank(body.getBodyType())) {
|
||||
body.setBodyType(Body.BodyType.XML.name());
|
||||
}
|
||||
XmlBody xml = new XmlBody();
|
||||
//xml.setValue(XMLUtils.jsonToXmlStr(jsonValue));
|
||||
body.setXmlBody(xml);
|
||||
}
|
||||
case MediaType.MULTIPART_FORM_DATA_VALUE -> {
|
||||
if (StringUtils.isBlank(body.getBodyType())) {
|
||||
body.setBodyType(Body.BodyType.FORM_DATA.name());
|
||||
}
|
||||
}
|
||||
case MediaType.APPLICATION_OCTET_STREAM_VALUE -> {
|
||||
if (StringUtils.isBlank(body.getBodyType())) {
|
||||
body.setBodyType(Body.BodyType.BINARY.name());
|
||||
}
|
||||
}
|
||||
case MediaType.TEXT_PLAIN_VALUE -> {
|
||||
if (StringUtils.isBlank(body.getBodyType())) {
|
||||
body.setBodyType(Body.BodyType.RAW.name());
|
||||
}
|
||||
RawBody rawBody = new RawBody();
|
||||
body.setRawBody(rawBody);
|
||||
}
|
||||
default -> body.setBodyType(Body.BodyType.NONE.name());
|
||||
}
|
||||
}
|
||||
|
||||
private void setBodyData(String k, io.swagger.v3.oas.models.media.MediaType value, Body body) {
|
||||
//TODO body 默认如果json格式
|
||||
JsonSchemaItem jsonSchemaItem = parseSchema(value.getSchema());
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
package io.metersphere.api.service;
|
||||
|
||||
import io.metersphere.api.constants.ApiResource;
|
||||
import io.metersphere.project.constants.ProjectMenuConstants;
|
||||
import io.metersphere.system.service.CommonProjectService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collections;
|
||||
|
@ -16,16 +14,7 @@ public class ApiValidateService {
|
|||
|
||||
//校验接口菜单是否开启
|
||||
public void validateApiMenuInProject(String resourceId, String resourceType) {
|
||||
String tableName = null;
|
||||
if (StringUtils.equals(resourceType, ApiResource.PROJECT.name())) {
|
||||
tableName = "project";
|
||||
} else if (StringUtils.equals(resourceType, ApiResource.API_DEFINITION.name())) {
|
||||
tableName = "api_definition";
|
||||
} else if (StringUtils.equals(resourceType, ApiResource.API_TEST_CASE.name())) {
|
||||
tableName = "api_test_case";
|
||||
} else if (StringUtils.equals(resourceType, ApiResource.API_SCENARIO.name())) {
|
||||
tableName = "api_scenario";
|
||||
}
|
||||
String tableName = resourceType.toLowerCase();
|
||||
commonProjectService.checkProjectHasModuleMenu(Collections.singletonList(ProjectMenuConstants.MODULE_MENU_API_TEST), resourceId, tableName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,24 +5,25 @@ 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.ApiDefinitionMockDTO;
|
||||
import io.metersphere.api.dto.definition.HttpResponse;
|
||||
import io.metersphere.api.dto.definition.request.ApiDefinitionMockAddRequest;
|
||||
import io.metersphere.api.dto.definition.request.ApiDefinitionMockPageRequest;
|
||||
import io.metersphere.api.dto.definition.request.ApiDefinitionMockRequest;
|
||||
import io.metersphere.api.dto.definition.request.ApiDefinitionMockUpdateRequest;
|
||||
import io.metersphere.api.dto.mockserver.MockMatchRule;
|
||||
import io.metersphere.api.dto.mockserver.MockResponse;
|
||||
import io.metersphere.api.mapper.ApiDefinitionMapper;
|
||||
import io.metersphere.api.mapper.ApiDefinitionMockConfigMapper;
|
||||
import io.metersphere.api.mapper.ApiDefinitionMockMapper;
|
||||
import io.metersphere.api.mapper.ExtApiDefinitionMockMapper;
|
||||
import io.metersphere.api.service.ApiFileResourceService;
|
||||
import io.metersphere.api.utils.ApiDataUtils;
|
||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||
import io.metersphere.project.service.ProjectService;
|
||||
import io.metersphere.sdk.constants.ApplicationNumScope;
|
||||
import io.metersphere.sdk.constants.DefaultRepositoryDir;
|
||||
import io.metersphere.sdk.exception.MSException;
|
||||
import io.metersphere.sdk.util.BeanUtils;
|
||||
import io.metersphere.sdk.util.FileAssociationSourceUtil;
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
import io.metersphere.system.log.constants.OperationLogModule;
|
||||
import io.metersphere.system.uid.IDGenerator;
|
||||
import io.metersphere.system.uid.NumGenerator;
|
||||
|
@ -31,7 +32,6 @@ import jakarta.annotation.Resource;
|
|||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
@ -68,7 +68,7 @@ public class ApiDefinitionMockService {
|
|||
ApiDefinitionMock apiDefinitionMock = checkApiDefinitionMock(request.getId());
|
||||
ApiDefinitionMockDTO apiDefinitionMockDTO = new ApiDefinitionMockDTO();
|
||||
handleMockConfig(request.getId(), apiDefinitionMockDTO);
|
||||
handleApiDefinition(request.getApiDefinitionId(), apiDefinitionMockDTO);
|
||||
handleApiDefinition(apiDefinitionMock.getApiDefinitionId(), apiDefinitionMockDTO);
|
||||
BeanUtils.copyBean(apiDefinitionMockDTO, apiDefinitionMock);
|
||||
return apiDefinitionMockDTO;
|
||||
}
|
||||
|
@ -76,8 +76,8 @@ public class ApiDefinitionMockService {
|
|||
public void handleMockConfig(String id, ApiDefinitionMockDTO apiDefinitionMockDTO) {
|
||||
Optional<ApiDefinitionMockConfig> apiDefinitionMockConfigOptional = Optional.ofNullable(apiDefinitionMockConfigMapper.selectByPrimaryKey(id));
|
||||
apiDefinitionMockConfigOptional.ifPresent(config -> {
|
||||
apiDefinitionMockDTO.setMatching(ApiDataUtils.parseObject(new String(config.getMatching()), AbstractMsTestElement.class));
|
||||
apiDefinitionMockDTO.setResponse(ApiDataUtils.parseArray(new String(config.getResponse()), HttpResponse.class));
|
||||
apiDefinitionMockDTO.setMatching(ApiDataUtils.parseObject(new String(config.getMatching()), MockMatchRule.class));
|
||||
apiDefinitionMockDTO.setResponse(ApiDataUtils.parseObject(new String(config.getResponse()), MockResponse.class));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -102,6 +102,13 @@ public class ApiDefinitionMockService {
|
|||
public ApiDefinitionMock create(ApiDefinitionMockAddRequest request, String userId) {
|
||||
ProjectService.checkResourceExist(request.getProjectId());
|
||||
|
||||
if (request.getMockMatchRule() == null) {
|
||||
request.setMockMatchRule(new MockMatchRule());
|
||||
}
|
||||
if (request.getResponse() == null) {
|
||||
request.setResponse(new MockResponse());
|
||||
}
|
||||
|
||||
ApiDefinitionMock apiDefinitionMock = new ApiDefinitionMock();
|
||||
BeanUtils.copyBean(apiDefinitionMock, request);
|
||||
checkAddExist(apiDefinitionMock);
|
||||
|
@ -119,8 +126,8 @@ public class ApiDefinitionMockService {
|
|||
apiDefinitionMockMapper.insertSelective(apiDefinitionMock);
|
||||
ApiDefinitionMockConfig apiDefinitionMockConfig = new ApiDefinitionMockConfig();
|
||||
apiDefinitionMockConfig.setId(apiDefinitionMock.getId());
|
||||
apiDefinitionMockConfig.setMatching(request.getMatching().getBytes());
|
||||
apiDefinitionMockConfig.setResponse(request.getResponse().getBytes());
|
||||
apiDefinitionMockConfig.setMatching(JSON.toJSONString(request.getMockMatchRule()).getBytes());
|
||||
apiDefinitionMockConfig.setResponse(JSON.toJSONString(request.getResponse()).getBytes());
|
||||
apiDefinitionMockConfigMapper.insertSelective(apiDefinitionMockConfig);
|
||||
|
||||
// 处理文件
|
||||
|
@ -176,8 +183,12 @@ public class ApiDefinitionMockService {
|
|||
apiDefinitionMockMapper.updateByPrimaryKeySelective(apiDefinitionMock);
|
||||
ApiDefinitionMockConfig apiDefinitionMockConfig = new ApiDefinitionMockConfig();
|
||||
apiDefinitionMockConfig.setId(apiDefinitionMock.getId());
|
||||
apiDefinitionMockConfig.setMatching(request.getMatching().getBytes());
|
||||
apiDefinitionMockConfig.setResponse(request.getResponse().getBytes());
|
||||
if (request.getMockMatchRule() != null) {
|
||||
apiDefinitionMockConfig.setMatching(JSON.toJSONString(request.getMockMatchRule()).getBytes());
|
||||
}
|
||||
if (request.getResponse() != null) {
|
||||
apiDefinitionMockConfig.setResponse(JSON.toJSONString(request.getResponse()).getBytes());
|
||||
}
|
||||
apiDefinitionMockConfigMapper.updateByPrimaryKeySelective(apiDefinitionMockConfig);
|
||||
|
||||
// 处理文件
|
||||
|
@ -244,10 +255,6 @@ public class ApiDefinitionMockService {
|
|||
apiDefinitionMockMapper.updateByPrimaryKeySelective(update);
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
@ -187,7 +187,11 @@ public class ApiDefinitionService {
|
|||
ApiDefinitionBlob apiDefinitionBlob = new ApiDefinitionBlob();
|
||||
apiDefinitionBlob.setId(apiDefinition.getId());
|
||||
apiDefinitionBlob.setRequest(getMsTestElementStr(request.getRequest()).getBytes());
|
||||
apiDefinitionBlob.setResponse(JSON.toJSONString(request.getResponse()).getBytes());
|
||||
if (request.getResponse() != null) {
|
||||
List<HttpResponse> msHttpResponse = JSON.parseArray(JSON.toJSONString(request.getResponse()), HttpResponse.class);
|
||||
msHttpResponse.forEach(item -> item.setId(IDGenerator.nextStr()));
|
||||
apiDefinitionBlob.setResponse(JSON.toJSONString(msHttpResponse).getBytes());
|
||||
}
|
||||
apiDefinitionBlobMapper.insertSelective(apiDefinitionBlob);
|
||||
|
||||
// 处理文件
|
||||
|
|
|
@ -0,0 +1,213 @@
|
|||
package io.metersphere.api.service.mockserver;
|
||||
|
||||
import io.metersphere.api.domain.*;
|
||||
import io.metersphere.api.dto.definition.HttpResponse;
|
||||
import io.metersphere.api.dto.definition.ResponseBody;
|
||||
import io.metersphere.api.dto.mockserver.HttpRequestParam;
|
||||
import io.metersphere.api.dto.mockserver.MockResponse;
|
||||
import io.metersphere.api.dto.request.http.Header;
|
||||
import io.metersphere.api.dto.request.http.body.Body;
|
||||
import io.metersphere.api.mapper.*;
|
||||
import io.metersphere.api.utils.MockServerUtils;
|
||||
import io.metersphere.project.domain.FileMetadata;
|
||||
import io.metersphere.project.mapper.FileMetadataMapper;
|
||||
import io.metersphere.project.service.FileManagementService;
|
||||
import io.metersphere.sdk.constants.DefaultRepositoryDir;
|
||||
import io.metersphere.sdk.constants.HttpMethodConstants;
|
||||
import io.metersphere.sdk.file.FileCenter;
|
||||
import io.metersphere.sdk.file.FileRepository;
|
||||
import io.metersphere.sdk.file.FileRequest;
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
import io.metersphere.sdk.util.LogUtils;
|
||||
import io.metersphere.sdk.util.TempFileUtils;
|
||||
import io.metersphere.sdk.util.Translator;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class MockServerService {
|
||||
|
||||
@Resource
|
||||
private ExtApiDefinitionMapper extApiDefinitionMapper;
|
||||
@Resource
|
||||
private ApiDefinitionBlobMapper apiDefinitionBlobMapper;
|
||||
@Resource
|
||||
private ApiDefinitionMockMapper apiDefinitionMockMapper;
|
||||
@Resource
|
||||
private ApiDefinitionMockConfigMapper apiDefinitionMockConfigMapper;
|
||||
@Resource
|
||||
private ApiFileResourceMapper apiFileResourceMapper;
|
||||
@Resource
|
||||
FileMetadataMapper fileMetadataMapper;
|
||||
@Resource
|
||||
FileManagementService fileManagementService;
|
||||
|
||||
private boolean isUrlParamMethod(String method) {
|
||||
return StringUtils.equalsAnyIgnoreCase(method, HttpMethodConstants.GET.name(), HttpMethodConstants.DELETE.name(), HttpMethodConstants.OPTIONS.name(), HttpMethodConstants.HEAD.name());
|
||||
}
|
||||
|
||||
|
||||
public Object execute(String method, Map<String, String> requestHeaderMap, String projectNum, String apiNumInfo, HttpServletRequest request, HttpServletResponse response) {
|
||||
ApiDefinition apiDefinition = extApiDefinitionMapper.selectByProjectNumAndApiNum(projectNum, apiNumInfo);
|
||||
if (apiDefinition == null) {
|
||||
return this.requestNotFound(response);
|
||||
}
|
||||
String url = request.getRequestURL().toString();
|
||||
String requestUrlSuffix = MockServerUtils.getUrlSuffix(StringUtils.joinWith("/", "/mock-server", projectNum, apiNumInfo), request);
|
||||
|
||||
if (StringUtils.equalsIgnoreCase(method, apiDefinition.getMethod()) && !MockServerUtils.checkUrlMatch(apiDefinition.getPath(), requestUrlSuffix)) {
|
||||
return this.requestNotFound(response);
|
||||
}
|
||||
HttpRequestParam requestMockParams = MockServerUtils.getHttpRequestParam(request, requestUrlSuffix, apiDefinition.getPath(), !this.isUrlParamMethod(method));
|
||||
LogUtils.info("Mock [" + url + "] Header:{}", requestHeaderMap);
|
||||
LogUtils.info("Mock [" + url + "] request:{}", JSON.toJSONString(requestMockParams));
|
||||
ApiDefinitionMockConfig compareMockConfig = this.match(apiDefinition.getId(), requestHeaderMap, requestMockParams);
|
||||
try {
|
||||
Object returnObj = this.getReturn(compareMockConfig, apiDefinition.getId(), apiDefinition.getProjectId(), response);
|
||||
return returnObj;
|
||||
} catch (Exception e) {
|
||||
return this.requestNotFound(response);
|
||||
}
|
||||
}
|
||||
|
||||
private ApiDefinitionMockConfig match(String apiId, Map<String, String> requestHeaderMap, HttpRequestParam requestMockParams) {
|
||||
ApiDefinitionMockConfig compareMockConfig = null;
|
||||
ApiDefinitionMockExample mockExample = new ApiDefinitionMockExample();
|
||||
mockExample.createCriteria().andApiDefinitionIdEqualTo(apiId).andEnableEqualTo(true);
|
||||
List<ApiDefinitionMock> apiDefinitionMockList = apiDefinitionMockMapper.selectByExample(mockExample);
|
||||
if (CollectionUtils.isNotEmpty(apiDefinitionMockList)) {
|
||||
ApiDefinitionMockConfigExample mockConfigExample = new ApiDefinitionMockConfigExample();
|
||||
mockConfigExample.createCriteria().andIdIn(apiDefinitionMockList.stream().map(ApiDefinitionMock::getId).toList());
|
||||
List<ApiDefinitionMockConfig> mockConfigs = apiDefinitionMockConfigMapper.selectByExampleWithBLOBs(mockConfigExample);
|
||||
for (ApiDefinitionMockConfig mockConfig : mockConfigs) {
|
||||
if (MockServerUtils.matchMockConfig(mockConfig.getMatching(), requestHeaderMap, requestMockParams)) {
|
||||
compareMockConfig = mockConfig;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return compareMockConfig;
|
||||
}
|
||||
|
||||
private Object getReturn(ApiDefinitionMockConfig compareMockConfig, String apiId, String projectId, HttpServletResponse response) {
|
||||
ResponseBody responseBody = null;
|
||||
List<Header> responseHeader = null;
|
||||
int responseCode = -1;
|
||||
String useApiResponseId = null;
|
||||
|
||||
if (compareMockConfig != null) {
|
||||
MockResponse mockResponse = JSON.parseObject(new String(compareMockConfig.getResponse()), MockResponse.class);
|
||||
if (mockResponse.isUseApiResponse()) {
|
||||
useApiResponseId = mockResponse.getApiResponseId();
|
||||
} else {
|
||||
responseCode = mockResponse.getStatusCode();
|
||||
responseHeader = mockResponse.getHeaders();
|
||||
responseBody = mockResponse.getBody();
|
||||
}
|
||||
}
|
||||
if (StringUtils.isNotBlank(useApiResponseId) || responseCode == -1) {
|
||||
HttpResponse mockSelectResponse = null;
|
||||
ApiDefinitionBlob blob = apiDefinitionBlobMapper.selectByPrimaryKey(apiId);
|
||||
if (blob != null) {
|
||||
List<HttpResponse> responseList = JSON.parseArray(new String(blob.getResponse()), HttpResponse.class);
|
||||
HttpResponse defaultHttpResponse = null;
|
||||
for (HttpResponse httpResponse : responseList) {
|
||||
if (httpResponse.isDefaultFlag()) {
|
||||
defaultHttpResponse = httpResponse;
|
||||
}
|
||||
if (StringUtils.equals(httpResponse.getId(), useApiResponseId)) {
|
||||
mockSelectResponse = httpResponse;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mockSelectResponse == null) {
|
||||
mockSelectResponse = defaultHttpResponse;
|
||||
}
|
||||
}
|
||||
if (mockSelectResponse == null) {
|
||||
return this.requestNotFound(response);
|
||||
} else {
|
||||
responseCode = Integer.parseInt(mockSelectResponse.getStatusCode());
|
||||
responseHeader = mockSelectResponse.getHeaders();
|
||||
responseBody = mockSelectResponse.getBody();
|
||||
}
|
||||
}
|
||||
|
||||
//返回响应码
|
||||
response.setStatus(responseCode);
|
||||
if (CollectionUtils.isNotEmpty(responseHeader)) {
|
||||
responseHeader.forEach(header -> {
|
||||
if (header.getEnable()) {
|
||||
response.addHeader(header.getKey(), header.getValue());
|
||||
}
|
||||
});
|
||||
}
|
||||
if (responseBody == null) {
|
||||
return StringUtils.EMPTY;
|
||||
} else {
|
||||
if (StringUtils.equalsIgnoreCase(responseBody.getBodyType(), Body.BodyType.JSON.name())) {
|
||||
return responseBody.getJsonBody().getJsonValue();
|
||||
} else if (StringUtils.equalsIgnoreCase(responseBody.getBodyType(), Body.BodyType.XML.name())) {
|
||||
return responseBody.getXmlBody().getValue();
|
||||
} else if (StringUtils.equalsIgnoreCase(responseBody.getBodyType(), Body.BodyType.RAW.name())) {
|
||||
return responseBody.getRawBody().getValue();
|
||||
} else {
|
||||
String fileId = responseBody.getBinaryBody().getFileId();
|
||||
String fileName = responseBody.getBinaryBody().getFileName();
|
||||
String fileType = StringUtils.substring(fileName, fileName.lastIndexOf(".") + 1);
|
||||
MediaType mediaType = MediaType.parseMediaType("application/octet-stream");
|
||||
if (responseBody.getBinaryBody().isSendAsBody()) {
|
||||
String contentType = "text/plain";
|
||||
if (TempFileUtils.isImage(fileType)) {
|
||||
contentType = "image/" + fileType;
|
||||
}
|
||||
mediaType = MediaType.parseMediaType(contentType);
|
||||
}
|
||||
byte[] bytes = new byte[0];
|
||||
FileMetadata fileMetadata = fileMetadataMapper.selectByPrimaryKey(fileId);
|
||||
if (fileMetadata != null) {
|
||||
try {
|
||||
String filePath = TempFileUtils.createFile(TempFileUtils.getTmpFilePath(fileMetadata.getId()), fileManagementService.getFile(fileMetadata));
|
||||
bytes = TempFileUtils.getFile(filePath);
|
||||
} catch (Exception ignore) {
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
} else {
|
||||
ApiFileResource apiFileResource = apiFileResourceMapper.selectByPrimaryKey(compareMockConfig.getId(), fileId);
|
||||
if (apiFileResource != null) {
|
||||
FileRepository defaultRepository = FileCenter.getDefaultRepository();
|
||||
FileRequest fileRequest = new FileRequest();
|
||||
fileRequest.setFileName(apiFileResource.getFileName());
|
||||
fileRequest.setFolder(DefaultRepositoryDir.getApiDefinitionDir(projectId, compareMockConfig.getId()) + "/" + fileId);
|
||||
try {
|
||||
bytes = defaultRepository.getFile(fileRequest);
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ResponseEntity.ok()
|
||||
.contentType(mediaType)
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"")
|
||||
.body(bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String requestNotFound(HttpServletResponse response) {
|
||||
response.setStatus(404);
|
||||
return Translator.get("mock_warning");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
package io.metersphere.api.utils;
|
||||
|
||||
import io.metersphere.api.dto.mockserver.HttpRequestParam;
|
||||
import io.metersphere.api.dto.mockserver.MockMatchRule;
|
||||
import io.metersphere.api.dto.request.http.body.Body;
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
import io.metersphere.sdk.util.LogUtils;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class MockServerUtils {
|
||||
|
||||
public static Map<String, String> getHttpRequestHeader(HttpServletRequest request) {
|
||||
Map<String, String> returnMap = new HashMap<>();
|
||||
Enumeration<String> headers = request.getHeaderNames();
|
||||
while (headers.hasMoreElements()) {
|
||||
String header = headers.nextElement();
|
||||
String headerValue = request.getHeader(header);
|
||||
returnMap.put(header, headerValue);
|
||||
}
|
||||
return returnMap;
|
||||
}
|
||||
|
||||
public static HttpRequestParam getHttpRequestParam(HttpServletRequest request, String requestUrlSuffix, String apiDefinitionPath, boolean isPost) {
|
||||
HttpRequestParam requestParam = new HttpRequestParam();
|
||||
requestParam.setPost(isPost);
|
||||
|
||||
LinkedHashMap<String, String> restParamMap = MockServerUtils.getRestParam(apiDefinitionPath, requestUrlSuffix);
|
||||
requestParam.setRestParams(restParamMap);
|
||||
|
||||
//解析k-v参数
|
||||
LinkedHashMap<String, String> queryParamsMap = new LinkedHashMap<>();
|
||||
Enumeration<String> paramNameItr = request.getParameterNames();
|
||||
while (paramNameItr.hasMoreElements()) {
|
||||
String key = paramNameItr.nextElement();
|
||||
String value = request.getParameter(key);
|
||||
queryParamsMap.put(key, value);
|
||||
}
|
||||
requestParam.setQueryParamsObj(queryParamsMap);
|
||||
|
||||
//解析body参数
|
||||
String requestPostString = getRequestStr(request);
|
||||
requestParam.setRaw(requestPostString);
|
||||
|
||||
//解析paramType
|
||||
if (StringUtils.startsWithIgnoreCase(request.getContentType(), "application/json")) {
|
||||
requestParam.setJsonParam(requestPostString);
|
||||
} else if (StringUtils.endsWith(request.getContentType(), "/xml")) {
|
||||
requestParam.setXmlParam(requestPostString);
|
||||
} else if (StringUtils.startsWithIgnoreCase(request.getContentType(), "application/x-www-form-urlencoded")) {
|
||||
requestParam.setParamType(Body.BodyType.FORM_DATA.name());
|
||||
} else if (StringUtils.startsWithIgnoreCase(request.getContentType(), "text/plain")) {
|
||||
requestParam.setParamType(Body.BodyType.RAW.name());
|
||||
} else if (isPost) {
|
||||
requestParam.setParamType(Body.BodyType.RAW.name());
|
||||
}
|
||||
return requestParam;
|
||||
}
|
||||
|
||||
public static LinkedHashMap<String, String> getRestParam(String apiPath, String requestUrl) {
|
||||
LinkedHashMap<String, String> restParams = new LinkedHashMap<>();
|
||||
if (StringUtils.isNotEmpty(apiPath)) {
|
||||
if (apiPath.startsWith("/")) {
|
||||
apiPath = apiPath.substring(1);
|
||||
}
|
||||
if (requestUrl.startsWith("/")) {
|
||||
requestUrl = requestUrl.substring(1);
|
||||
}
|
||||
String[] pathArr = apiPath.split("/");
|
||||
String[] sendParamArr = requestUrl.split("/");
|
||||
|
||||
//获取 url的<参数名-参数值>,通过匹配api的接口设置和实际发送的url
|
||||
for (int i = 0; i < pathArr.length; i++) {
|
||||
String param = pathArr[i];
|
||||
if (param.startsWith("{") && param.endsWith("}")) {
|
||||
param = param.substring(1, param.length() - 1);
|
||||
String value = StringUtils.EMPTY;
|
||||
if (sendParamArr.length > i) {
|
||||
value = sendParamArr[i];
|
||||
}
|
||||
restParams.put(param, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return restParams;
|
||||
}
|
||||
|
||||
private static String getRequestStr(HttpServletRequest request) {
|
||||
String inputLine;
|
||||
// 接收到的数据
|
||||
StringBuilder receiveData = new StringBuilder();
|
||||
try (BufferedReader in = new BufferedReader(new InputStreamReader(
|
||||
request.getInputStream(), StandardCharsets.UTF_8))) {
|
||||
while ((inputLine = in.readLine()) != null) {
|
||||
receiveData.append(inputLine);
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
|
||||
return receiveData.toString();
|
||||
}
|
||||
|
||||
public static String getUrlSuffix(String mockUrlInfo, HttpServletRequest request) {
|
||||
String requestUri = request.getRequestURI();
|
||||
String[] urlParamArr = requestUri.split(mockUrlInfo);
|
||||
return urlParamArr.length == 0 ? "" : urlParamArr[urlParamArr.length - 1];
|
||||
}
|
||||
|
||||
public static boolean checkUrlMatch(String apiDefinitionPath, String requestUrlSuffix) {
|
||||
if (StringUtils.equalsAny(apiDefinitionPath, requestUrlSuffix, "/" + requestUrlSuffix)) {
|
||||
return true;
|
||||
} else {
|
||||
if (StringUtils.isNotEmpty(apiDefinitionPath)) {
|
||||
|
||||
String urlSuffix = requestUrlSuffix;
|
||||
//去掉前缀的“/"
|
||||
if (urlSuffix.startsWith("/")) {
|
||||
urlSuffix = urlSuffix.substring(1);
|
||||
}
|
||||
if (apiDefinitionPath.startsWith("/")) {
|
||||
apiDefinitionPath = apiDefinitionPath.substring(1);
|
||||
}
|
||||
|
||||
//如果请求后缀以"/"结尾,需要特殊处理
|
||||
boolean urlSuffixEndEmpty = false;
|
||||
if (urlSuffix.endsWith("/")) {
|
||||
urlSuffixEndEmpty = true;
|
||||
urlSuffix = urlSuffix + "emptyStrForSplit";
|
||||
}
|
||||
String[] requestUrlDomainArr = urlSuffix.split("/");
|
||||
if (urlSuffixEndEmpty) {
|
||||
requestUrlDomainArr[requestUrlDomainArr.length - 1] = StringUtils.EMPTY;
|
||||
}
|
||||
urlSuffixEndEmpty = false;
|
||||
if (apiDefinitionPath.endsWith("/")) {
|
||||
urlSuffixEndEmpty = true;
|
||||
apiDefinitionPath = apiDefinitionPath + "emptyStrForSplit";
|
||||
}
|
||||
String[] apiPathDomainArr = apiDefinitionPath.split("/");
|
||||
if (urlSuffixEndEmpty) {
|
||||
apiPathDomainArr[apiPathDomainArr.length - 1] = StringUtils.EMPTY;
|
||||
}
|
||||
|
||||
if (apiPathDomainArr.length == requestUrlDomainArr.length) {
|
||||
boolean isFetch = true;
|
||||
for (int i = 0; i < requestUrlDomainArr.length; i++) {
|
||||
String pathItem = apiPathDomainArr[i];
|
||||
if (!(pathItem.startsWith("{") && pathItem.endsWith("}"))) {
|
||||
if (!StringUtils.equals(apiPathDomainArr[i], requestUrlDomainArr[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return isFetch;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean matchMockConfig(byte[] mockMatchBytes, Map<String, String> requestHeaderMap, HttpRequestParam httpRequestParam) {
|
||||
try {
|
||||
MockMatchRule matchRule = JSON.parseObject(new String(mockMatchBytes), MockMatchRule.class);
|
||||
return matchRule.keyValueMatch("header", requestHeaderMap) && matchRule.requestParamMatch(httpRequestParam);
|
||||
} catch (Exception e) {
|
||||
LogUtils.info(e.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,57 +1,68 @@
|
|||
package io.metersphere.api.controller;
|
||||
|
||||
import io.metersphere.api.constants.ApiConstants;
|
||||
import io.metersphere.api.constants.ApiDefinitionStatus;
|
||||
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.ApiFileResource;
|
||||
import io.metersphere.api.dto.definition.ApiDefinitionAddRequest;
|
||||
import io.metersphere.api.dto.definition.ApiDefinitionMockDTO;
|
||||
import io.metersphere.api.dto.definition.HttpResponse;
|
||||
import io.metersphere.api.domain.*;
|
||||
import io.metersphere.api.dto.definition.*;
|
||||
import io.metersphere.api.dto.definition.request.ApiDefinitionMockAddRequest;
|
||||
import io.metersphere.api.dto.definition.request.ApiDefinitionMockPageRequest;
|
||||
import io.metersphere.api.dto.definition.request.ApiDefinitionMockRequest;
|
||||
import io.metersphere.api.dto.definition.request.ApiDefinitionMockUpdateRequest;
|
||||
import io.metersphere.api.dto.mockserver.KeyValueInfo;
|
||||
import io.metersphere.api.dto.mockserver.MockMatchRule;
|
||||
import io.metersphere.api.dto.mockserver.MockResponse;
|
||||
import io.metersphere.api.dto.request.http.Header;
|
||||
import io.metersphere.api.dto.request.http.MsHTTPElement;
|
||||
import io.metersphere.api.mapper.ApiDefinitionMapper;
|
||||
import io.metersphere.api.mapper.ApiDefinitionMockConfigMapper;
|
||||
import io.metersphere.api.mapper.ApiDefinitionMockMapper;
|
||||
import io.metersphere.api.dto.request.http.body.Body;
|
||||
import io.metersphere.api.mapper.*;
|
||||
import io.metersphere.api.service.ApiFileResourceService;
|
||||
import io.metersphere.api.service.MockServerTestService;
|
||||
import io.metersphere.api.utils.ApiDataUtils;
|
||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||
import io.metersphere.project.dto.filemanagement.FileInfo;
|
||||
import io.metersphere.project.domain.FileMetadata;
|
||||
import io.metersphere.project.dto.filemanagement.request.FileUploadRequest;
|
||||
import io.metersphere.project.service.FileAssociationService;
|
||||
import io.metersphere.project.mapper.ExtBaseProjectVersionMapper;
|
||||
import io.metersphere.project.mapper.FileMetadataMapper;
|
||||
import io.metersphere.project.service.FileManagementService;
|
||||
import io.metersphere.project.service.FileMetadataService;
|
||||
import io.metersphere.sdk.constants.DefaultRepositoryDir;
|
||||
import io.metersphere.sdk.constants.HttpMethodConstants;
|
||||
import io.metersphere.sdk.constants.ModuleConstants;
|
||||
import io.metersphere.sdk.constants.PermissionConstants;
|
||||
import io.metersphere.sdk.file.FileCenter;
|
||||
import io.metersphere.sdk.file.FileRepository;
|
||||
import io.metersphere.sdk.file.FileRequest;
|
||||
import io.metersphere.sdk.util.BeanUtils;
|
||||
import io.metersphere.sdk.util.CommonBeanFactory;
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
import io.metersphere.sdk.util.LogUtils;
|
||||
import io.metersphere.sdk.util.TempFileUtils;
|
||||
import io.metersphere.system.base.BaseTest;
|
||||
import io.metersphere.system.controller.handler.ResultHolder;
|
||||
import io.metersphere.system.controller.handler.result.MsHttpResultCode;
|
||||
import io.metersphere.system.log.constants.OperationLogType;
|
||||
import io.metersphere.system.utils.Pager;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
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.MockHttpServletResponse;
|
||||
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;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
||||
import org.testcontainers.shaded.org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.*;
|
||||
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
|
||||
@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
|
@ -71,26 +82,60 @@ public class ApiDefinitionMockControllerTests extends BaseTest {
|
|||
private static final String UPLOAD_TEMP_FILE = BASE_PATH + "/upload/temp/file";
|
||||
|
||||
private static final String DEFAULT_API_ID = "1001";
|
||||
private static Long NO_MOCK_NO_RESPONSE_API_NUM;
|
||||
|
||||
private static ApiDefinitionMock apiDefinitionMock;
|
||||
|
||||
@Resource
|
||||
private MockServerTestService mockServerTestService;
|
||||
@Resource
|
||||
private ApiDefinitionMapper apiDefinitionMapper;
|
||||
@Resource
|
||||
private ApiDefinitionBlobMapper apiDefinitionBlobMapper;
|
||||
@Resource
|
||||
private ApiDefinitionMockMapper apiDefinitionMockMapper;
|
||||
|
||||
@Resource
|
||||
private ApiDefinitionMockConfigMapper apiDefinitionMockConfigMapper;
|
||||
|
||||
@Resource
|
||||
private ExtBaseProjectVersionMapper extBaseProjectVersionMapper;
|
||||
@Resource
|
||||
private ApiFileResourceService apiFileResourceService;
|
||||
|
||||
@Resource
|
||||
private FileMetadataMapper fileMetadataMapper;
|
||||
@Resource
|
||||
private FileManagementService fileManagementService;
|
||||
@Resource
|
||||
private FileMetadataService fileMetadataService;
|
||||
@Resource
|
||||
private ApiFileResourceMapper apiFileResourceMapper;
|
||||
|
||||
//文件管理中已存在的ID
|
||||
private static String fileMetadataId;
|
||||
private static String uploadFileId;
|
||||
|
||||
private static Map<String, ApiDefinition> METHOD_API_MAP = new LinkedHashMap<>();
|
||||
private static Map<ApiDefinition, List<ApiDefinitionMock>> API_MOCK_MAP = new LinkedHashMap<>();
|
||||
|
||||
private static String[] HTTP_METHODS = {"POST", "GET", "HEAD", "PUT", "PATCH", "DELETE", "OPTIONS", "TRACE"};
|
||||
|
||||
/**
|
||||
* 文件管理插入一条数据
|
||||
* 便于测试关联文件
|
||||
*/
|
||||
private void uploadFileMetadata() throws Exception {
|
||||
FileUploadRequest fileUploadRequest = new FileUploadRequest();
|
||||
fileUploadRequest.setProjectId(DEFAULT_PROJECT_ID);
|
||||
//导入正常文件
|
||||
MockMultipartFile file = new MockMultipartFile("file", "mock_file_upload.JPG", MediaType.APPLICATION_OCTET_STREAM_VALUE, "file-metadata.file".getBytes());
|
||||
fileMetadataId = fileMetadataService.upload(fileUploadRequest, "admin", file);
|
||||
}
|
||||
|
||||
public String doUploadTempFile(MockMultipartFile file) throws Exception {
|
||||
return JSON.parseObject(requestUploadFileWithOkAndReturn(UPLOAD_TEMP_FILE, file)
|
||||
.getResponse()
|
||||
.getContentAsString(), ResultHolder.class)
|
||||
.getData().toString();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(0)
|
||||
|
@ -98,7 +143,7 @@ public class ApiDefinitionMockControllerTests extends BaseTest {
|
|||
// 准备数据,上传文件管理文件
|
||||
uploadFileMetadata();
|
||||
// @@请求成功
|
||||
MockMultipartFile file = getMockMultipartFile("file_upload.JPG");
|
||||
MockMultipartFile file = mockServerTestService.getMockMultipartFile("file_upload.JPG");
|
||||
String fileId = doUploadTempFile(file);
|
||||
|
||||
// 校验文件存在
|
||||
|
@ -109,95 +154,69 @@ public class ApiDefinitionMockControllerTests extends BaseTest {
|
|||
|
||||
requestUploadPermissionTest(PermissionConstants.PROJECT_API_DEFINITION_MOCK_ADD, UPLOAD_TEMP_FILE, file);
|
||||
requestUploadPermissionTest(PermissionConstants.PROJECT_API_DEFINITION_MOCK_UPDATE, UPLOAD_TEMP_FILE, file);
|
||||
}
|
||||
|
||||
private String doUploadTempFile(MockMultipartFile file) throws Exception {
|
||||
return JSON.parseObject(requestUploadFileWithOkAndReturn(UPLOAD_TEMP_FILE, file)
|
||||
.getResponse()
|
||||
.getContentAsString(), ResultHolder.class)
|
||||
.getData().toString();
|
||||
}
|
||||
// 这个api是用于测试没有配置任何mock以及默认响应的情况
|
||||
String defaultVersion = extBaseProjectVersionMapper.getDefaultVersion(DEFAULT_PROJECT_ID);
|
||||
ApiDefinitionAddRequest noMockNoResponseApiRequest = new ApiDefinitionAddRequest();
|
||||
noMockNoResponseApiRequest.setName("MockApi_No_Response");
|
||||
noMockNoResponseApiRequest.setProtocol(ApiConstants.HTTP_PROTOCOL);
|
||||
noMockNoResponseApiRequest.setProjectId(DEFAULT_PROJECT_ID);
|
||||
noMockNoResponseApiRequest.setMethod("GET");
|
||||
noMockNoResponseApiRequest.setPath("/mock/api/notMatch/");
|
||||
noMockNoResponseApiRequest.setStatus(ApiDefinitionStatus.PREPARE.getValue());
|
||||
noMockNoResponseApiRequest.setModuleId(ModuleConstants.DEFAULT_NODE_ID);
|
||||
noMockNoResponseApiRequest.setVersionId(defaultVersion);
|
||||
noMockNoResponseApiRequest.setDescription("desc");
|
||||
noMockNoResponseApiRequest.setRequest(JSON.parseObject(ApiDataUtils.toJSONString(MsHTTPElementTest.getMsHttpElement())));
|
||||
noMockNoResponseApiRequest.setResponse(new ArrayList<>());
|
||||
NO_MOCK_NO_RESPONSE_API_NUM = getResultData(this.requestPostWithOkAndReturn("/api/definition/add", noMockNoResponseApiRequest), ApiDefinition.class).getNum();
|
||||
|
||||
private static MockMultipartFile getMockMultipartFile(String fileName) {
|
||||
return new MockMultipartFile(
|
||||
"file",
|
||||
fileName,
|
||||
MediaType.APPLICATION_OCTET_STREAM_VALUE,
|
||||
"Hello, World!".getBytes()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件管理插入一条数据
|
||||
* 便于测试关联文件
|
||||
*/
|
||||
private void uploadFileMetadata() throws Exception {
|
||||
FileUploadRequest fileUploadRequest = new FileUploadRequest();
|
||||
fileUploadRequest.setProjectId(DEFAULT_PROJECT_ID);
|
||||
//导入正常文件
|
||||
MockMultipartFile file = new MockMultipartFile("file", "mock_file_upload.JPG", MediaType.APPLICATION_OCTET_STREAM_VALUE, "mock".getBytes());
|
||||
fileMetadataId = fileMetadataService.upload(fileUploadRequest, "admin", file);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验上传的文件
|
||||
* @param id
|
||||
* @param fileIds 全部的文件ID
|
||||
*/
|
||||
public static void assertUploadFile(String id, List<String> fileIds) throws Exception {
|
||||
if (fileIds != null) {
|
||||
ApiFileResourceService apiFileResourceService = CommonBeanFactory.getBean(ApiFileResourceService.class);
|
||||
// 验证文件的关联关系,以及是否存入对象存储
|
||||
List<ApiFileResource> apiFileResources = apiFileResourceService.getByResourceId(id);
|
||||
Assertions.assertEquals(apiFileResources.size(), fileIds.size());
|
||||
|
||||
String apiDefinitionDir = DefaultRepositoryDir.getApiDefinitionDir(DEFAULT_PROJECT_ID, id);
|
||||
FileRequest fileRequest = new FileRequest();
|
||||
if (!fileIds.isEmpty()) {
|
||||
for (ApiFileResource apiFileResource : apiFileResources) {
|
||||
Assertions.assertEquals(DEFAULT_PROJECT_ID, apiFileResource.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)));
|
||||
if (MapUtils.isEmpty(METHOD_API_MAP)) {
|
||||
for (String method : HTTP_METHODS) {
|
||||
// 创建并返回一个 ApiDefinitionAddRequest 对象,用于测试
|
||||
ApiDefinitionAddRequest request = new ApiDefinitionAddRequest();
|
||||
request.setName("MockApi:" + method);
|
||||
request.setProtocol(ApiConstants.HTTP_PROTOCOL);
|
||||
request.setProjectId(DEFAULT_PROJECT_ID);
|
||||
request.setMethod(method);
|
||||
request.setPath("/mock/api/" + method + "/{param1}/{param2}");
|
||||
request.setStatus(ApiDefinitionStatus.PREPARE.getValue());
|
||||
request.setModuleId(ModuleConstants.DEFAULT_NODE_ID);
|
||||
request.setVersionId(defaultVersion);
|
||||
request.setDescription("desc");
|
||||
MsHTTPElement msHttpElement = MsHTTPElementTest.getMsHttpElement();
|
||||
request.setRequest(JSON.parseObject(ApiDataUtils.toJSONString(msHttpElement)));
|
||||
request.setResponse(MsHTTPElementTest.get2MsHttpResponse(request.getPath()));
|
||||
MvcResult mvcResult = this.requestPostWithOkAndReturn("/api/definition/add", request);
|
||||
ApiDefinition resultData = getResultData(mvcResult, ApiDefinition.class);
|
||||
METHOD_API_MAP.put(method, resultData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验上传的文件
|
||||
* @param id
|
||||
* @param fileIds 全部的文件ID
|
||||
*/
|
||||
private static void assertLinkFile(String id, List<String> fileIds) {
|
||||
FileAssociationService fileAssociationService = CommonBeanFactory.getBean(FileAssociationService.class);
|
||||
List<String> linkFileIds = fileAssociationService.getFiles(id)
|
||||
.stream()
|
||||
.map(FileInfo::getFileId)
|
||||
.toList();
|
||||
Assertions.assertEquals(fileIds, linkFileIds);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(1)
|
||||
@Sql(scripts = {"/dml/init_api_definition.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED))
|
||||
public void testAdd() throws Exception {
|
||||
|
||||
LogUtils.info("create api mock test");
|
||||
// 创建测试数据
|
||||
ApiDefinitionMockAddRequest request = new ApiDefinitionMockAddRequest();
|
||||
request.setName("接口定义test");
|
||||
request.setProjectId(DEFAULT_PROJECT_ID);
|
||||
request.setApiDefinitionId(DEFAULT_API_ID);
|
||||
MsHTTPElement msHttpElement = MsHTTPElementTest.getMsHttpElement();
|
||||
request.setMatching(ApiDataUtils.toJSONString(msHttpElement));
|
||||
List<HttpResponse> msHttpResponse = MsHTTPElementTest.getMsHttpResponse();
|
||||
request.setResponse(ApiDataUtils.toJSONString(msHttpResponse));
|
||||
|
||||
uploadFileId = doUploadTempFile(getMockMultipartFile("file_upload.JPG"));
|
||||
MockMatchRule mockMatchRule = new MockMatchRule();
|
||||
request.setMockMatchRule(mockMatchRule);
|
||||
uploadFileId = doUploadTempFile(mockServerTestService.getMockMultipartFile("file_upload.JPG"));
|
||||
MockResponse mockResponse = new MockResponse();
|
||||
mockResponse.setBody(new ResponseBody() {{
|
||||
this.setBinaryBody(new ResponseBinaryBody() {{
|
||||
this.setFileId(uploadFileId);
|
||||
this.setFileName("file_upload.JPG");
|
||||
}});
|
||||
}});
|
||||
request.setResponse(mockResponse);
|
||||
request.setUploadFileIds(List.of(uploadFileId));
|
||||
request.setLinkFileIds(List.of(fileMetadataId));
|
||||
|
||||
|
@ -205,9 +224,9 @@ public class ApiDefinitionMockControllerTests extends BaseTest {
|
|||
MvcResult mvcResult = this.requestPostWithOkAndReturn(ADD, request);
|
||||
// 校验请求成功数据
|
||||
ApiDefinitionMock resultData = getResultData(mvcResult, ApiDefinitionMock.class);
|
||||
apiDefinitionMock = assertAddApiDefinitionMock(request, msHttpElement, resultData.getId());
|
||||
assertUploadFile(apiDefinitionMock.getId(), List.of(uploadFileId));
|
||||
assertLinkFile(apiDefinitionMock.getId(), List.of(fileMetadataId));
|
||||
apiDefinitionMock = mockServerTestService.assertAddApiDefinitionMock(request, mockMatchRule, resultData.getId());
|
||||
mockServerTestService.assertUploadFile(apiDefinitionMock.getId(), List.of(uploadFileId));
|
||||
mockServerTestService.assertLinkFile(apiDefinitionMock.getId(), List.of(fileMetadataId));
|
||||
|
||||
// 再插入一条数据,便于修改时重名校验
|
||||
request.setName("重名接口定义test");
|
||||
|
@ -216,7 +235,7 @@ public class ApiDefinitionMockControllerTests extends BaseTest {
|
|||
request.setLinkFileIds(null);
|
||||
mvcResult = this.requestPostWithOkAndReturn(ADD, request);
|
||||
resultData = getResultData(mvcResult, ApiDefinitionMock.class);
|
||||
assertAddApiDefinitionMock(request, msHttpElement, resultData.getId());
|
||||
mockServerTestService.assertAddApiDefinitionMock(request, mockMatchRule, resultData.getId());
|
||||
// @@重名校验异常
|
||||
assertErrorCode(this.requestPost(ADD, request), ApiResultCode.API_DEFINITION_MOCK_EXIST);
|
||||
|
||||
|
@ -233,19 +252,9 @@ public class ApiDefinitionMockControllerTests extends BaseTest {
|
|||
request.setProjectId(DEFAULT_PROJECT_ID);
|
||||
request.setName("permission-st-6");
|
||||
requestPostPermissionTest(PermissionConstants.PROJECT_API_DEFINITION_MOCK_ADD, ADD, request);
|
||||
|
||||
}
|
||||
|
||||
private ApiDefinitionMock assertAddApiDefinitionMock(Object request, MsHTTPElement msHttpElement, String id) {
|
||||
ApiDefinitionMock apiDefinitionMock = apiDefinitionMockMapper.selectByPrimaryKey(id);
|
||||
ApiDefinitionMockConfig apiDefinitionMockConfig = apiDefinitionMockConfigMapper.selectByPrimaryKey(id);
|
||||
ApiDefinitionMock copyApiDefinitionMock = BeanUtils.copyBean(new ApiDefinitionMock(), apiDefinitionMock);
|
||||
BeanUtils.copyBean(copyApiDefinitionMock, request);
|
||||
Assertions.assertEquals(apiDefinitionMock, copyApiDefinitionMock);
|
||||
if(apiDefinitionMockConfig != null){
|
||||
Assertions.assertEquals(msHttpElement, ApiDataUtils.parseObject(new String(apiDefinitionMockConfig.getMatching()), AbstractMsTestElement.class));
|
||||
}
|
||||
return apiDefinitionMock;
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(2)
|
||||
|
@ -253,7 +262,6 @@ public class ApiDefinitionMockControllerTests extends BaseTest {
|
|||
ApiDefinitionMockRequest apiDefinitionMockRequest = new ApiDefinitionMockRequest();
|
||||
apiDefinitionMockRequest.setId(apiDefinitionMock.getId());
|
||||
apiDefinitionMockRequest.setProjectId(DEFAULT_PROJECT_ID);
|
||||
apiDefinitionMockRequest.setApiDefinitionId(apiDefinitionMock.getApiDefinitionId());
|
||||
// @@请求成功
|
||||
MvcResult mvcResult = this.requestPostWithOkAndReturn(DETAIL, apiDefinitionMockRequest);
|
||||
ApiDefinitionMockDTO apiDefinitionMockDTO = ApiDataUtils.parseObject(JSON.toJSONString(parseResponse(mvcResult).get("data")), ApiDefinitionMockDTO.class);
|
||||
|
@ -269,8 +277,8 @@ public class ApiDefinitionMockControllerTests extends BaseTest {
|
|||
|
||||
ApiDefinitionMockConfig apiDefinitionMockConfig = apiDefinitionMockConfigMapper.selectByPrimaryKey(apiDefinitionMock.getId());
|
||||
if(apiDefinitionMockConfig != null){
|
||||
copyApiDefinitionMockDTO.setMatching(ApiDataUtils.parseObject(new String(apiDefinitionMockConfig.getMatching()), AbstractMsTestElement.class));
|
||||
copyApiDefinitionMockDTO.setResponse(ApiDataUtils.parseArray(new String(apiDefinitionMockConfig.getResponse()), HttpResponse.class));
|
||||
copyApiDefinitionMockDTO.setMatching(ApiDataUtils.parseObject(new String(apiDefinitionMockConfig.getMatching()), MockMatchRule.class));
|
||||
copyApiDefinitionMockDTO.setResponse(ApiDataUtils.parseObject(new String(apiDefinitionMockConfig.getResponse()), MockResponse.class));
|
||||
}
|
||||
Assertions.assertEquals(apiDefinitionMockDTO, copyApiDefinitionMockDTO);
|
||||
|
||||
|
@ -287,14 +295,12 @@ public class ApiDefinitionMockControllerTests extends BaseTest {
|
|||
public void testUpdate() throws Exception {
|
||||
LogUtils.info("update api mock test");
|
||||
|
||||
MockMatchRule mockMatchRule = new MockMatchRule();
|
||||
ApiDefinitionMockUpdateRequest request = new ApiDefinitionMockUpdateRequest();
|
||||
BeanUtils.copyBean(request, apiDefinitionMock);
|
||||
request.setName("test1test1test1test1test1test1");
|
||||
|
||||
MsHTTPElement msHttpElement = MsHTTPElementTest.getMsHttpElement();
|
||||
request.setMatching(ApiDataUtils.toJSONString(msHttpElement));
|
||||
List<HttpResponse> msHttpResponse = MsHTTPElementTest.getMsHttpResponse();
|
||||
request.setResponse(ApiDataUtils.toJSONString(msHttpResponse));
|
||||
request.setMockMatchRule(mockMatchRule);
|
||||
request.setResponse(new MockResponse());
|
||||
|
||||
// 清除文件的更新
|
||||
request.setUnLinkRefIds(List.of(fileMetadataId));
|
||||
|
@ -302,43 +308,43 @@ public class ApiDefinitionMockControllerTests extends BaseTest {
|
|||
|
||||
this.requestPostWithOk(UPDATE, request);
|
||||
// 校验请求成功数据
|
||||
apiDefinitionMock = assertAddApiDefinitionMock(request, msHttpElement, request.getId());
|
||||
assertUploadFile(apiDefinitionMock.getId(), List.of());
|
||||
assertLinkFile(apiDefinitionMock.getId(), List.of());
|
||||
apiDefinitionMock = mockServerTestService.assertAddApiDefinitionMock(request, mockMatchRule, request.getId());
|
||||
mockServerTestService.assertUploadFile(apiDefinitionMock.getId(), List.of());
|
||||
mockServerTestService.assertLinkFile(apiDefinitionMock.getId(), List.of());
|
||||
|
||||
// 带文件的更新
|
||||
String fileId = doUploadTempFile(getMockMultipartFile("file_upload.JPG"));
|
||||
String fileId = doUploadTempFile(mockServerTestService.getMockMultipartFile("file_upload.JPG"));
|
||||
request.setUploadFileIds(List.of(fileId));
|
||||
request.setLinkFileIds(List.of(fileMetadataId));
|
||||
request.setDeleteFileIds(null);
|
||||
request.setUnLinkRefIds(null);
|
||||
this.requestPostWithOk(UPDATE, request);
|
||||
// 校验请求成功数据
|
||||
apiDefinitionMock = assertAddApiDefinitionMock(request, msHttpElement, request.getId());
|
||||
assertUploadFile(apiDefinitionMock.getId(), List.of(fileId));
|
||||
assertLinkFile(apiDefinitionMock.getId(), List.of(fileMetadataId));
|
||||
apiDefinitionMock = mockServerTestService.assertAddApiDefinitionMock(request, mockMatchRule, request.getId());
|
||||
mockServerTestService.assertUploadFile(apiDefinitionMock.getId(), List.of(fileId));
|
||||
mockServerTestService.assertLinkFile(apiDefinitionMock.getId(), List.of(fileMetadataId));
|
||||
|
||||
// 删除了上一次上传的文件,重新上传一个文件
|
||||
request.setDeleteFileIds(List.of(fileId));
|
||||
String newFileId1 = doUploadTempFile(getMockMultipartFile("file_upload.JPG"));
|
||||
String newFileId1 = doUploadTempFile(mockServerTestService.getMockMultipartFile("file_upload.JPG"));
|
||||
request.setUploadFileIds(List.of(newFileId1));
|
||||
request.setUnLinkRefIds(List.of(fileMetadataId));
|
||||
request.setLinkFileIds(List.of(fileMetadataId));
|
||||
this.requestPostWithOk(UPDATE, request);
|
||||
apiDefinitionMock = assertAddApiDefinitionMock(request, msHttpElement, request.getId());
|
||||
assertUploadFile(apiDefinitionMock.getId(), List.of(newFileId1));
|
||||
assertLinkFile(apiDefinitionMock.getId(), List.of(fileMetadataId));
|
||||
apiDefinitionMock = mockServerTestService.assertAddApiDefinitionMock(request, mockMatchRule, request.getId());
|
||||
mockServerTestService.assertUploadFile(apiDefinitionMock.getId(), List.of(newFileId1));
|
||||
mockServerTestService.assertLinkFile(apiDefinitionMock.getId(), List.of(fileMetadataId));
|
||||
|
||||
// 已有一个文件,再上传一个文件
|
||||
String newFileId2 = doUploadTempFile(getMockMultipartFile("file_update_upload.JPG"));
|
||||
String newFileId2 = doUploadTempFile(mockServerTestService.getMockMultipartFile("file_update_upload.JPG"));
|
||||
request.setUploadFileIds(List.of(newFileId2));
|
||||
request.setUnLinkRefIds(null);
|
||||
request.setDeleteFileIds(null);
|
||||
request.setLinkFileIds(null);
|
||||
this.requestPostWithOk(UPDATE, request);
|
||||
apiDefinitionMock = assertAddApiDefinitionMock(request, msHttpElement, request.getId());
|
||||
assertUploadFile(apiDefinitionMock.getId(), List.of(newFileId1, newFileId2));
|
||||
assertLinkFile(apiDefinitionMock.getId(), List.of(fileMetadataId));
|
||||
apiDefinitionMock = mockServerTestService.assertAddApiDefinitionMock(request, mockMatchRule, request.getId());
|
||||
mockServerTestService.assertUploadFile(apiDefinitionMock.getId(), List.of(newFileId1, newFileId2));
|
||||
mockServerTestService.assertLinkFile(apiDefinitionMock.getId(), List.of(fileMetadataId));
|
||||
// 修改 tags
|
||||
request.setUploadFileIds(null);
|
||||
request.setUnLinkRefIds(null);
|
||||
|
@ -346,14 +352,10 @@ public class ApiDefinitionMockControllerTests extends BaseTest {
|
|||
request.setLinkFileIds(null);
|
||||
request.setTags(new LinkedHashSet<>(List.of("tag1", "tag2-update")));
|
||||
request.setName("接口定义test接口定义test接口定义test接口定义test接口定义test接口定义test接口定义test接口定义test接口定义test接口定义test接口定义test接口定义test接口定义test接口定义test接口定义test接口定义test接口定义test接口定义test接口定义test接口定义test接口定义test接口定义test接口定义test接口定义test接口定义test");
|
||||
MsHTTPElement msHttpElementTag = MsHTTPElementTest.getMsHttpElement();
|
||||
request.setMatching(ApiDataUtils.toJSONString(msHttpElementTag));
|
||||
List<HttpResponse> msHttpResponseTag = MsHTTPElementTest.getMsHttpResponse();
|
||||
request.setResponse(ApiDataUtils.toJSONString(msHttpResponseTag));
|
||||
|
||||
this.requestPostWithOk(UPDATE, request);
|
||||
// 校验请求成功数据
|
||||
assertAddApiDefinitionMock(request, msHttpElement, request.getId());
|
||||
mockServerTestService.assertAddApiDefinitionMock(request, mockMatchRule, request.getId());
|
||||
|
||||
request.setName("重名接口定义test");
|
||||
// @@重名校验异常
|
||||
|
@ -367,7 +369,7 @@ public class ApiDefinitionMockControllerTests extends BaseTest {
|
|||
// 校验数据是否存在
|
||||
request.setId("111");
|
||||
request.setName("test123");
|
||||
assertErrorCode(this.requestPost(UPDATE, request), MsHttpResultCode.NOT_FOUND);
|
||||
this.requestPost(UPDATE, request).andExpect(status().is5xxServerError());
|
||||
|
||||
// @@校验日志
|
||||
checkLog(apiDefinitionMock.getId(), OperationLogType.UPDATE, UPDATE);
|
||||
|
@ -393,7 +395,7 @@ public class ApiDefinitionMockControllerTests extends BaseTest {
|
|||
// @@校验日志
|
||||
checkLog(apiDefinitionMock.getId(), OperationLogType.UPDATE, ENABLE + apiDefinitionMock.getId());
|
||||
|
||||
assertErrorCode(this.requestGet(ENABLE + "111"), MsHttpResultCode.NOT_FOUND);
|
||||
assertErrorCode(this.requestGet(ENABLE + "111"), MsHttpResultCode.FAILED);
|
||||
|
||||
// @@开启
|
||||
// @@请求成功
|
||||
|
@ -403,7 +405,7 @@ public class ApiDefinitionMockControllerTests extends BaseTest {
|
|||
// @@校验日志
|
||||
checkLog(apiDefinitionMock.getId(), OperationLogType.UPDATE, ENABLE + apiDefinitionMock.getId());
|
||||
|
||||
assertErrorCode(this.requestGet(ENABLE + "111"), MsHttpResultCode.NOT_FOUND);
|
||||
assertErrorCode(this.requestGet(ENABLE + "111"), MsHttpResultCode.FAILED);
|
||||
// @@校验权限
|
||||
requestGetPermissionTest(PermissionConstants.PROJECT_API_DEFINITION_MOCK_UPDATE, ENABLE + apiDefinitionMock.getId());
|
||||
}
|
||||
|
@ -415,7 +417,6 @@ public class ApiDefinitionMockControllerTests extends BaseTest {
|
|||
ApiDefinitionMockRequest request = new ApiDefinitionMockRequest();
|
||||
request.setId(apiDefinitionMock.getId());
|
||||
request.setProjectId(DEFAULT_PROJECT_ID);
|
||||
request.setApiDefinitionId(apiDefinitionMock.getApiDefinitionId());
|
||||
MvcResult mvcResult = this.requestPostWithOkAndReturn(COPY, request);
|
||||
ApiDefinitionMock resultData = getResultData(mvcResult, ApiDefinitionMock.class);
|
||||
// @数据验证
|
||||
|
@ -426,28 +427,10 @@ public class ApiDefinitionMockControllerTests extends BaseTest {
|
|||
}
|
||||
Assertions.assertTrue(resultData.getName().contains("copy_"));
|
||||
|
||||
ApiDefinitionMockUpdateRequest apiDefinitionMockUpdateRequest = new ApiDefinitionMockUpdateRequest();
|
||||
BeanUtils.copyBean(apiDefinitionMockUpdateRequest, apiDefinitionMock);
|
||||
apiDefinitionMockUpdateRequest.setName("test1test1test1test1test1test1");
|
||||
|
||||
MsHTTPElement msHttpElement = MsHTTPElementTest.getMsHttpElement();
|
||||
apiDefinitionMockUpdateRequest.setMatching(ApiDataUtils.toJSONString(msHttpElement));
|
||||
List<HttpResponse> msHttpResponse = MsHTTPElementTest.getMsHttpResponse();
|
||||
apiDefinitionMockUpdateRequest.setResponse(ApiDataUtils.toJSONString(msHttpResponse));
|
||||
|
||||
this.requestPostWithOk(UPDATE, apiDefinitionMockUpdateRequest);
|
||||
// 校验请求成功数据
|
||||
apiDefinitionMock = assertAddApiDefinitionMock(request, msHttpElement, request.getId());
|
||||
request.setId(apiDefinitionMock.getId());
|
||||
MvcResult mvcResultCopy = this.requestPostWithOkAndReturn(COPY, request);
|
||||
ApiDefinitionMock resultDataCopy = getResultData(mvcResultCopy, ApiDefinitionMock.class);
|
||||
// @数据验证
|
||||
Assertions.assertTrue(resultDataCopy.getName().contains("copy_"));
|
||||
|
||||
// @@校验日志
|
||||
checkLog(resultData.getId(), OperationLogType.UPDATE);
|
||||
request.setId("121");
|
||||
assertErrorCode(this.requestPost(COPY, request), MsHttpResultCode.NOT_FOUND);
|
||||
assertErrorCode(this.requestPost(COPY, request), MsHttpResultCode.FAILED);
|
||||
// @@校验权限
|
||||
request.setId(apiDefinitionMock.getId());
|
||||
requestPostPermissionTest(PermissionConstants.PROJECT_API_DEFINITION_MOCK_UPDATE, COPY, request);
|
||||
|
@ -511,7 +494,6 @@ public class ApiDefinitionMockControllerTests extends BaseTest {
|
|||
ApiDefinitionMockRequest apiDefinitionMockRequest = new ApiDefinitionMockRequest();
|
||||
apiDefinitionMockRequest.setId(apiDefinitionMock.getId());
|
||||
apiDefinitionMockRequest.setProjectId(DEFAULT_PROJECT_ID);
|
||||
apiDefinitionMockRequest.setApiDefinitionId(apiDefinitionMock.getApiDefinitionId());
|
||||
// @@请求成功
|
||||
this.requestPostWithOkAndReturn(DELETE, apiDefinitionMockRequest);
|
||||
checkLog(apiDefinitionMock.getId(), OperationLogType.DELETE);
|
||||
|
@ -528,12 +510,433 @@ public class ApiDefinitionMockControllerTests extends BaseTest {
|
|||
|
||||
checkLog(apiDefinitionMockRequest.getId(), OperationLogType.DELETE);
|
||||
apiDefinitionMockRequest.setId("121");
|
||||
assertErrorCode(this.requestPost(DELETE, apiDefinitionMockRequest), MsHttpResultCode.NOT_FOUND);
|
||||
assertErrorCode(this.requestPost(DELETE, apiDefinitionMockRequest), MsHttpResultCode.FAILED);
|
||||
// @@校验权限
|
||||
requestPostPermissionTest(PermissionConstants.PROJECT_API_DEFINITION_MOCK_DELETE, DELETE, apiDefinitionMockRequest);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(99)
|
||||
public void mockServerTest() throws Exception {
|
||||
this.initMockConfigTestData();
|
||||
|
||||
//测试匹配不到任何一个api
|
||||
mockServerTestService.testNoMatchApi();
|
||||
//测试匹配到了api但是路径不一样
|
||||
mockServerTestService.testApiNoMockConfigAndNoResponse("/mock-server/100001/" + NO_MOCK_NO_RESPONSE_API_NUM + "/mock/api/testStr/");
|
||||
//测试匹配到的api没用配置mockConfig以及没有定义默认返回项
|
||||
mockServerTestService.testApiNoMockConfigAndNoResponse("/mock-server/100001/" + NO_MOCK_NO_RESPONSE_API_NUM + "/mock/api/notMatch/");
|
||||
|
||||
/*
|
||||
测试用例:
|
||||
* rest全匹配: 返回接口定义的响应
|
||||
* rest半匹配: 尝试返回文件
|
||||
* header全匹配: 尝试返回body-xml
|
||||
* header半匹配: 尝试返回body-json
|
||||
* get类型的请求测试: Query全匹配 Query半匹配
|
||||
* post类型的请求测试: Body-kv全匹配、Body-kv半匹配、Body-json包含匹配、Body-xml包含匹配、RAW包含匹配
|
||||
*/
|
||||
for (Map.Entry<ApiDefinition, List<ApiDefinitionMock>> entry : API_MOCK_MAP.entrySet()) {
|
||||
ApiDefinition apiDefinition = entry.getKey();
|
||||
List<ApiDefinitionMock> apiDefinitionMockList = entry.getValue();
|
||||
|
||||
String method = apiDefinition.getMethod();
|
||||
if (StringUtils.equalsIgnoreCase(method, "TRACE")) {
|
||||
//这种不测试
|
||||
continue;
|
||||
}
|
||||
String url = "/mock-server/100001/" + apiDefinition.getNum() + apiDefinition.getPath();
|
||||
//先做一个没有匹配到任何的mock期望的测试
|
||||
mockServerTestService.testNoMatchMockConfig(method, url, apiDefinition.getPath());
|
||||
|
||||
for (ApiDefinitionMock mock : apiDefinitionMockList) {
|
||||
//重置url
|
||||
url = "/mock-server/100001/" + apiDefinition.getNum() + apiDefinition.getPath();
|
||||
|
||||
ApiDefinitionBlob apiDefinitionBlob = apiDefinitionBlobMapper.selectByPrimaryKey(apiDefinition.getId());
|
||||
ApiDefinitionMockConfig mockConfig = apiDefinitionMockConfigMapper.selectByPrimaryKey(mock.getId());
|
||||
MockMatchRule mockMatchRule = JSON.parseObject(new String(mockConfig.getMatching()), MockMatchRule.class);
|
||||
MockResponse mockResponse = JSON.parseObject(new String(mockConfig.getResponse()), MockResponse.class);
|
||||
List<HttpResponse> apiResponseList = JSON.parseArray(new String(apiDefinitionBlob.getResponse()), HttpResponse.class);
|
||||
HttpResponse MockUseApiRsponse = null;
|
||||
for (HttpResponse apiResponse : apiResponseList) {
|
||||
if (mockResponse.isUseApiResponse() && StringUtils.equals(mockResponse.getApiResponseId(), apiResponse.getId())) {
|
||||
MockUseApiRsponse = apiResponse;
|
||||
}
|
||||
}
|
||||
String[] mockNameArr = mock.getName().split("_");
|
||||
String methodType = mockNameArr[1]; //
|
||||
String conditionType = mockNameArr[2];
|
||||
|
||||
//替换rest参数
|
||||
for (KeyValueInfo keyValueInfo : mockMatchRule.getRest().getMatchRules()) {
|
||||
url = StringUtils.replace(url, "{" + keyValueInfo.getKey() + "}", keyValueInfo.getValue());
|
||||
}
|
||||
|
||||
//设置query参数
|
||||
StringBuilder queryParamBuilder = new StringBuilder();
|
||||
if (CollectionUtils.isNotEmpty(mockMatchRule.getQuery().getMatchRules())) {
|
||||
for (KeyValueInfo keyValueInfo : mockMatchRule.getQuery().getMatchRules()) {
|
||||
if (!queryParamBuilder.isEmpty()) {
|
||||
queryParamBuilder.append("&");
|
||||
}
|
||||
queryParamBuilder.append(keyValueInfo.getKey());
|
||||
queryParamBuilder.append("=");
|
||||
queryParamBuilder.append(keyValueInfo.getValue());
|
||||
if (!mockMatchRule.getQuery().isMatchAll()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
url = url + "?" + queryParamBuilder;
|
||||
}
|
||||
|
||||
//开始创建请求
|
||||
MockHttpServletRequestBuilder requestBuilder = mockServerTestService.getRequestBuilder(method, url);
|
||||
|
||||
//设置请求头 如果匹配类型是body-json或者body-xml,需要设置content-type
|
||||
if (StringUtils.equalsIgnoreCase(conditionType, "body-json")) {
|
||||
requestBuilder.header("content-type", "application/json");
|
||||
} else if (StringUtils.equalsIgnoreCase(conditionType, "body-xml")) {
|
||||
requestBuilder.header("content-type", "application/xml");
|
||||
} else if (StringUtils.equalsIgnoreCase(conditionType, "body-kv-x-www")) {
|
||||
requestBuilder.header("content-type", "application/x-www-form-urlencoded");
|
||||
} else if (StringUtils.equalsIgnoreCase(conditionType, "Body-raw")) {
|
||||
requestBuilder.header("content-type", "text/plain");
|
||||
}
|
||||
|
||||
if (CollectionUtils.isNotEmpty(mockMatchRule.getHeader().getMatchRules())) {
|
||||
for (KeyValueInfo keyValueInfo : mockMatchRule.getHeader().getMatchRules()) {
|
||||
requestBuilder.header(keyValueInfo.getKey(), keyValueInfo.getValue());
|
||||
if (!mockMatchRule.getHeader().isMatchAll()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//设置body参数 (get类型的请求不设置)
|
||||
if (this.isNotGetTypeMethod(methodType) && StringUtils.equalsIgnoreCase(mockMatchRule.getBody().getParamType(), Body.BodyType.FORM_DATA.name())) {
|
||||
for (KeyValueInfo keyValueInfo : mockMatchRule.getBody().getFormDataMatch().getMatchRules()) {
|
||||
requestBuilder.param(keyValueInfo.getKey(), keyValueInfo.getValue());
|
||||
if (!mockMatchRule.getBody().getFormDataMatch().isMatchAll()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (StringUtils.isNotBlank(mockMatchRule.getBody().getRaw())) {
|
||||
requestBuilder.content(mockMatchRule.getBody().getRaw());
|
||||
}
|
||||
|
||||
//发送请求
|
||||
ResultActions action = mockMvc.perform(requestBuilder);
|
||||
|
||||
//判断响应
|
||||
List<Header> headers;
|
||||
int statusCode;
|
||||
ResponseBody responseBody;
|
||||
if (mockResponse.isUseApiResponse()) {
|
||||
headers = MockUseApiRsponse.getHeaders();
|
||||
statusCode = Integer.parseInt(MockUseApiRsponse.getStatusCode());
|
||||
responseBody = MockUseApiRsponse.getBody();
|
||||
} else {
|
||||
headers = mockResponse.getHeaders();
|
||||
statusCode = mockResponse.getStatusCode();
|
||||
responseBody = mockResponse.getBody();
|
||||
}
|
||||
|
||||
MockHttpServletResponse mockServerResponse = action.andReturn().getResponse();
|
||||
//判断响应码
|
||||
Assertions.assertEquals(mockServerResponse.getStatus(), statusCode);
|
||||
//判断响应头
|
||||
for (Header header : headers) {
|
||||
if (header.getEnable()) {
|
||||
Assertions.assertEquals(mockServerResponse.getHeader(header.getKey()), header.getValue());
|
||||
}
|
||||
}
|
||||
//判断响应体
|
||||
if (StringUtils.equals(responseBody.getBodyType(), Body.BodyType.BINARY.name())) {
|
||||
byte[] returnFileBytes = mockServerResponse.getContentAsByteArray();
|
||||
String fileId = responseBody.getBinaryBody().getFileId();
|
||||
byte[] bytes = new byte[0];
|
||||
FileMetadata fileMetadata = fileMetadataMapper.selectByPrimaryKey(fileId);
|
||||
if (fileMetadata != null) {
|
||||
String filePath = TempFileUtils.createFile(TempFileUtils.getTmpFilePath(fileMetadata.getId()), fileManagementService.getFile(fileMetadata));
|
||||
bytes = TempFileUtils.getFile(filePath);
|
||||
} else {
|
||||
ApiFileResource apiFileResource = apiFileResourceMapper.selectByPrimaryKey(mock.getId(), fileId);
|
||||
if (apiFileResource != null) {
|
||||
FileRepository defaultRepository = FileCenter.getDefaultRepository();
|
||||
FileRequest fileRequest = new FileRequest();
|
||||
fileRequest.setFileName(apiFileResource.getFileName());
|
||||
fileRequest.setFolder(DefaultRepositoryDir.getApiDefinitionDir(apiDefinition.getProjectId(), mock.getId()) + "/" + fileId);
|
||||
try {
|
||||
bytes = defaultRepository.getFile(fileRequest);
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//通过MD5判断是否是同一个文件
|
||||
String fileMD5 = this.getFileMD5(bytes);
|
||||
String downloadMD5 = this.getFileMD5(returnFileBytes);
|
||||
Assertions.assertEquals(fileMD5, downloadMD5);
|
||||
|
||||
} else {
|
||||
String returnStr = mockServerResponse.getContentAsString(StandardCharsets.UTF_8);
|
||||
String compareStr = "";
|
||||
switch (responseBody.getBodyType()) {
|
||||
case "JSON":
|
||||
compareStr = responseBody.getJsonBody().getJsonValue();
|
||||
break;
|
||||
case "XML":
|
||||
compareStr = responseBody.getXmlBody().getValue();
|
||||
break;
|
||||
case "RAW":
|
||||
compareStr = responseBody.getRawBody().getValue();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Assertions.assertEquals(returnStr, compareStr);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean isNotGetTypeMethod(String methodType) {
|
||||
return !StringUtils.equalsAnyIgnoreCase(methodType, HttpMethodConstants.GET.name(), HttpMethodConstants.DELETE.name(), HttpMethodConstants.OPTIONS.name(), HttpMethodConstants.HEAD.name());
|
||||
}
|
||||
|
||||
private void initMockConfigTestData() throws Exception {
|
||||
if (MapUtils.isEmpty(METHOD_API_MAP)) {
|
||||
this.uploadTempFile();
|
||||
}
|
||||
|
||||
//为METHOD_API_MAP每个api创建一个mock期望,用于做mockServer的测试
|
||||
for (Map.Entry<String, ApiDefinition> apiDefinitionEntry : METHOD_API_MAP.entrySet()) {
|
||||
String method = apiDefinitionEntry.getKey();
|
||||
ApiDefinition apiDefinition = apiDefinitionEntry.getValue();
|
||||
ApiDefinitionBlob apiDefinitionBlob = apiDefinitionBlobMapper.selectByPrimaryKey(apiDefinition.getId());
|
||||
|
||||
List<ApiDefinitionMock> mockList = new ArrayList<>();
|
||||
//rest全匹配 返回接口定义的响应
|
||||
{
|
||||
ApiDefinitionMockAddRequest mockServerRequest = new ApiDefinitionMockAddRequest();
|
||||
mockServerRequest.setName("Mock_" + method + "_Rest_Full_Match1");
|
||||
mockServerRequest.setProjectId(apiDefinition.getProjectId());
|
||||
mockServerRequest.setApiDefinitionId(apiDefinition.getId());
|
||||
mockServerRequest.setMockMatchRule(mockServerTestService.genMockMatchRule("Rest_Full_Match1", false, true, null, true));
|
||||
mockServerRequest.setResponse(mockServerTestService.genMockResponse(null, 444, "Rest_Full_Match1", uploadFileId, null, apiDefinitionBlob));
|
||||
MvcResult mockServerResult = this.requestPostWithOkAndReturn(ADD, mockServerRequest);
|
||||
ApiDefinitionMock definitionMock = getResultData(mockServerResult, ApiDefinitionMock.class);
|
||||
mockServerTestService.assertAddApiDefinitionMock(mockServerRequest, mockServerRequest.getMockMatchRule(), definitionMock.getId());
|
||||
mockList.add(definitionMock);
|
||||
}
|
||||
|
||||
//rest全匹配 返回本地上传的文件(send by body)
|
||||
{
|
||||
String mockFileMatch2Id = doUploadTempFile(mockServerTestService.getMockMultipartFile("mockFileMatch2.txt", "mockFileMatch2"));
|
||||
|
||||
ApiDefinitionMockAddRequest mockServerRequest = new ApiDefinitionMockAddRequest();
|
||||
mockServerRequest.setName("Mock_" + method + "_Rest_Full_Match2");
|
||||
mockServerRequest.setProjectId(apiDefinition.getProjectId());
|
||||
mockServerRequest.setApiDefinitionId(apiDefinition.getId());
|
||||
mockServerRequest.setMockMatchRule(mockServerTestService.genMockMatchRule("Rest_Full_Match2", false, true, null, false));
|
||||
mockServerRequest.setResponse(mockServerTestService.genMockResponse("file-body", 200, "Rest_Full_Match2", mockFileMatch2Id, "mockFileMatch2.txt", null));
|
||||
|
||||
mockServerRequest.setUploadFileIds(List.of(mockFileMatch2Id));
|
||||
|
||||
MvcResult mockServerResult = this.requestPostWithOkAndReturn(ADD, mockServerRequest);
|
||||
ApiDefinitionMock definitionMock = getResultData(mockServerResult, ApiDefinitionMock.class);
|
||||
mockServerTestService.assertAddApiDefinitionMock(mockServerRequest, mockServerRequest.getMockMatchRule(), definitionMock.getId());
|
||||
mockList.add(definitionMock);
|
||||
|
||||
|
||||
}
|
||||
|
||||
//rest全匹配 返回本地上传的文件(send by download)
|
||||
{
|
||||
String mockFileMatch3Id = doUploadTempFile(mockServerTestService.getMockMultipartFile("mockFileMatch3.txt", "mockFileMatch3"));
|
||||
|
||||
ApiDefinitionMockAddRequest mockServerRequest = new ApiDefinitionMockAddRequest();
|
||||
mockServerRequest.setName("Mock_" + method + "_Rest_Full_Match3");
|
||||
mockServerRequest.setProjectId(apiDefinition.getProjectId());
|
||||
mockServerRequest.setApiDefinitionId(apiDefinition.getId());
|
||||
mockServerRequest.setMockMatchRule(mockServerTestService.genMockMatchRule("Rest_Full_Match3", false, true, null, false));
|
||||
mockServerRequest.setResponse(mockServerTestService.genMockResponse("file", 200, "Rest_Full_Match3", mockFileMatch3Id, "mockFileMatch3.txt", null));
|
||||
|
||||
mockServerRequest.setUploadFileIds(List.of(mockFileMatch3Id));
|
||||
|
||||
MvcResult mockServerResult = this.requestPostWithOkAndReturn(ADD, mockServerRequest);
|
||||
ApiDefinitionMock definitionMock = getResultData(mockServerResult, ApiDefinitionMock.class);
|
||||
mockServerTestService.assertAddApiDefinitionMock(mockServerRequest, mockServerRequest.getMockMatchRule(), definitionMock.getId());
|
||||
mockList.add(definitionMock);
|
||||
}
|
||||
|
||||
//rest全匹配 返回文件管理的文件(send by download)
|
||||
{
|
||||
ApiDefinitionMockAddRequest mockServerRequest = new ApiDefinitionMockAddRequest();
|
||||
mockServerRequest.setName("Mock_" + method + "_Rest_Full_Match4");
|
||||
mockServerRequest.setProjectId(apiDefinition.getProjectId());
|
||||
mockServerRequest.setApiDefinitionId(apiDefinition.getId());
|
||||
mockServerRequest.setMockMatchRule(mockServerTestService.genMockMatchRule("Rest_Full_Match4", false, true, null, false));
|
||||
mockServerRequest.setResponse(mockServerTestService.genMockResponse("file", 200, "Rest_Full_Match4", fileMetadataId, "fileMetadata.txt", null));
|
||||
mockServerRequest.setLinkFileIds(List.of(fileMetadataId));
|
||||
|
||||
MvcResult mockServerResult = this.requestPostWithOkAndReturn(ADD, mockServerRequest);
|
||||
ApiDefinitionMock definitionMock = getResultData(mockServerResult, ApiDefinitionMock.class);
|
||||
mockServerTestService.assertAddApiDefinitionMock(mockServerRequest, mockServerRequest.getMockMatchRule(), definitionMock.getId());
|
||||
mockList.add(definitionMock);
|
||||
}
|
||||
|
||||
//header全匹配 尝试返回body-xml
|
||||
{
|
||||
ApiDefinitionMockAddRequest mockServerRequest = new ApiDefinitionMockAddRequest();
|
||||
mockServerRequest.setName("Mock_" + method + "_Header_Full_Match");
|
||||
mockServerRequest.setProjectId(apiDefinition.getProjectId());
|
||||
mockServerRequest.setApiDefinitionId(apiDefinition.getId());
|
||||
mockServerRequest.setMockMatchRule(mockServerTestService.genMockMatchRule("Header_Full_Match", false, false, null, true));
|
||||
mockServerRequest.setResponse(mockServerTestService.genMockResponse("xml", 201, "Header_Full_Match", uploadFileId, null, null));
|
||||
MvcResult mockServerResult = this.requestPostWithOkAndReturn(ADD, mockServerRequest);
|
||||
ApiDefinitionMock definitionMock = getResultData(mockServerResult, ApiDefinitionMock.class);
|
||||
mockServerTestService.assertAddApiDefinitionMock(mockServerRequest, mockServerRequest.getMockMatchRule(), definitionMock.getId());
|
||||
mockList.add(definitionMock);
|
||||
}
|
||||
|
||||
//header半匹配 尝试返回body-json
|
||||
{
|
||||
ApiDefinitionMockAddRequest mockServerRequest = new ApiDefinitionMockAddRequest();
|
||||
mockServerRequest.setName("Mock_" + method + "_Header_Half_Match");
|
||||
mockServerRequest.setProjectId(apiDefinition.getProjectId());
|
||||
mockServerRequest.setApiDefinitionId(apiDefinition.getId());
|
||||
mockServerRequest.setMockMatchRule(mockServerTestService.genMockMatchRule("Header_Half_Match", false, false, null, false));
|
||||
mockServerRequest.setResponse(mockServerTestService.genMockResponse("json", 202, "Header_Half_Match", uploadFileId, null, null));
|
||||
MvcResult mockServerResult = this.requestPostWithOkAndReturn(ADD, mockServerRequest);
|
||||
ApiDefinitionMock definitionMock = getResultData(mockServerResult, ApiDefinitionMock.class);
|
||||
mockServerTestService.assertAddApiDefinitionMock(mockServerRequest, mockServerRequest.getMockMatchRule(), definitionMock.getId());
|
||||
mockList.add(definitionMock);
|
||||
}
|
||||
|
||||
//query全匹配
|
||||
{
|
||||
ApiDefinitionMockAddRequest mockServerRequest = new ApiDefinitionMockAddRequest();
|
||||
mockServerRequest.setName("Mock_" + method + "_Query_Full_Match");
|
||||
mockServerRequest.setProjectId(apiDefinition.getProjectId());
|
||||
mockServerRequest.setApiDefinitionId(apiDefinition.getId());
|
||||
mockServerRequest.setMockMatchRule(mockServerTestService.genMockMatchRule("Query_Full_Match", true, true, null, true));
|
||||
mockServerRequest.setResponse(mockServerTestService.genMockResponse("raw", 203, "Query_Full_Match", uploadFileId, null, null));
|
||||
MvcResult mockServerResult = this.requestPostWithOkAndReturn(ADD, mockServerRequest);
|
||||
ApiDefinitionMock definitionMock = getResultData(mockServerResult, ApiDefinitionMock.class);
|
||||
mockServerTestService.assertAddApiDefinitionMock(mockServerRequest, mockServerRequest.getMockMatchRule(), definitionMock.getId());
|
||||
mockList.add(definitionMock);
|
||||
}
|
||||
|
||||
//query半匹配
|
||||
{
|
||||
ApiDefinitionMockAddRequest mockServerRequest = new ApiDefinitionMockAddRequest();
|
||||
mockServerRequest.setName("Mock_" + method + "_Query_Half_Match");
|
||||
mockServerRequest.setProjectId(apiDefinition.getProjectId());
|
||||
mockServerRequest.setApiDefinitionId(apiDefinition.getId());
|
||||
mockServerRequest.setMockMatchRule(mockServerTestService.genMockMatchRule("Query_Half_Match", true, true, null, false));
|
||||
mockServerRequest.setResponse(mockServerTestService.genMockResponse("raw", 204, "Query_Half_Match", uploadFileId, null, null));
|
||||
MvcResult mockServerResult = this.requestPostWithOkAndReturn(ADD, mockServerRequest);
|
||||
ApiDefinitionMock definitionMock = getResultData(mockServerResult, ApiDefinitionMock.class);
|
||||
mockServerTestService.assertAddApiDefinitionMock(mockServerRequest, mockServerRequest.getMockMatchRule(), definitionMock.getId());
|
||||
mockList.add(definitionMock);
|
||||
}
|
||||
|
||||
//body-kv 全匹配
|
||||
{
|
||||
ApiDefinitionMockAddRequest mockServerRequest = new ApiDefinitionMockAddRequest();
|
||||
mockServerRequest.setName("Mock_" + method + "_Body-kv_Full_Match");
|
||||
mockServerRequest.setProjectId(apiDefinition.getProjectId());
|
||||
mockServerRequest.setApiDefinitionId(apiDefinition.getId());
|
||||
mockServerRequest.setMockMatchRule(mockServerTestService.genMockMatchRule("Body-kv_Full_Match", false, true, "kv", true));
|
||||
mockServerRequest.setResponse(mockServerTestService.genMockResponse("raw", 204, "Body-kv_Full_Match", uploadFileId, null, null));
|
||||
MvcResult mockServerResult = this.requestPostWithOkAndReturn(ADD, mockServerRequest);
|
||||
ApiDefinitionMock definitionMock = getResultData(mockServerResult, ApiDefinitionMock.class);
|
||||
mockServerTestService.assertAddApiDefinitionMock(mockServerRequest, mockServerRequest.getMockMatchRule(), definitionMock.getId());
|
||||
mockList.add(definitionMock);
|
||||
}
|
||||
//body-kv 半匹配
|
||||
{
|
||||
ApiDefinitionMockAddRequest mockServerRequest = new ApiDefinitionMockAddRequest();
|
||||
mockServerRequest.setName("Mock_" + method + "_Body-kv_Half_Match");
|
||||
mockServerRequest.setProjectId(apiDefinition.getProjectId());
|
||||
mockServerRequest.setApiDefinitionId(apiDefinition.getId());
|
||||
mockServerRequest.setMockMatchRule(mockServerTestService.genMockMatchRule("Body-kv_Half_Match", false, true, "kv", false));
|
||||
mockServerRequest.setResponse(mockServerTestService.genMockResponse("raw", 204, "Body-kv_Half_Match", uploadFileId, null, null));
|
||||
MvcResult mockServerResult = this.requestPostWithOkAndReturn(ADD, mockServerRequest);
|
||||
ApiDefinitionMock definitionMock = getResultData(mockServerResult, ApiDefinitionMock.class);
|
||||
mockServerTestService.assertAddApiDefinitionMock(mockServerRequest, mockServerRequest.getMockMatchRule(), definitionMock.getId());
|
||||
mockList.add(definitionMock);
|
||||
}
|
||||
//body-kv 半匹配x-www-form-urlencoded
|
||||
{
|
||||
ApiDefinitionMockAddRequest mockServerRequest = new ApiDefinitionMockAddRequest();
|
||||
mockServerRequest.setName("Mock_" + method + "_Body-kv-x-www_Half_Match");
|
||||
mockServerRequest.setProjectId(apiDefinition.getProjectId());
|
||||
mockServerRequest.setApiDefinitionId(apiDefinition.getId());
|
||||
mockServerRequest.setMockMatchRule(mockServerTestService.genMockMatchRule("Body-kv-x-www_Half_Match", false, true, "kv", false));
|
||||
mockServerRequest.setResponse(mockServerTestService.genMockResponse("raw", 204, "Body-kv-x-www_Half_Match", uploadFileId, null, null));
|
||||
MvcResult mockServerResult = this.requestPostWithOkAndReturn(ADD, mockServerRequest);
|
||||
ApiDefinitionMock definitionMock = getResultData(mockServerResult, ApiDefinitionMock.class);
|
||||
mockServerTestService.assertAddApiDefinitionMock(mockServerRequest, mockServerRequest.getMockMatchRule(), definitionMock.getId());
|
||||
mockList.add(definitionMock);
|
||||
}
|
||||
|
||||
//body-json包含匹配
|
||||
{
|
||||
ApiDefinitionMockAddRequest mockServerRequest = new ApiDefinitionMockAddRequest();
|
||||
mockServerRequest.setName("Mock_" + method + "_Body-json_Half_Match");
|
||||
mockServerRequest.setProjectId(apiDefinition.getProjectId());
|
||||
mockServerRequest.setApiDefinitionId(apiDefinition.getId());
|
||||
mockServerRequest.setMockMatchRule(mockServerTestService.genMockMatchRule("Body-json_Half_Match", false, true, "json", false));
|
||||
mockServerRequest.setResponse(mockServerTestService.genMockResponse("raw", 204, "Body-json_Half_Match", uploadFileId, null, null));
|
||||
MvcResult mockServerResult = this.requestPostWithOkAndReturn(ADD, mockServerRequest);
|
||||
ApiDefinitionMock definitionMock = getResultData(mockServerResult, ApiDefinitionMock.class);
|
||||
mockServerTestService.assertAddApiDefinitionMock(mockServerRequest, mockServerRequest.getMockMatchRule(), definitionMock.getId());
|
||||
mockList.add(definitionMock);
|
||||
}
|
||||
//body-xml包含匹配
|
||||
{
|
||||
ApiDefinitionMockAddRequest mockServerRequest = new ApiDefinitionMockAddRequest();
|
||||
mockServerRequest.setName("Mock_" + method + "_Body-xml_Half_Match");
|
||||
mockServerRequest.setProjectId(apiDefinition.getProjectId());
|
||||
mockServerRequest.setApiDefinitionId(apiDefinition.getId());
|
||||
mockServerRequest.setMockMatchRule(mockServerTestService.genMockMatchRule("Body-xml_Half_Match", false, true, "xml", false));
|
||||
mockServerRequest.setResponse(mockServerTestService.genMockResponse("raw", 204, "Body-xml_Half_Match", uploadFileId, null, null));
|
||||
MvcResult mockServerResult = this.requestPostWithOkAndReturn(ADD, mockServerRequest);
|
||||
ApiDefinitionMock definitionMock = getResultData(mockServerResult, ApiDefinitionMock.class);
|
||||
mockServerTestService.assertAddApiDefinitionMock(mockServerRequest, mockServerRequest.getMockMatchRule(), definitionMock.getId());
|
||||
mockList.add(definitionMock);
|
||||
}
|
||||
//raw包含匹配
|
||||
{
|
||||
ApiDefinitionMockAddRequest mockServerRequest = new ApiDefinitionMockAddRequest();
|
||||
mockServerRequest.setName("Mock_" + method + "_Body-raw_Half_Match");
|
||||
mockServerRequest.setProjectId(apiDefinition.getProjectId());
|
||||
mockServerRequest.setApiDefinitionId(apiDefinition.getId());
|
||||
mockServerRequest.setMockMatchRule(mockServerTestService.genMockMatchRule("body-raw_Half_Match", false, true, "raw", false));
|
||||
mockServerRequest.setResponse(mockServerTestService.genMockResponse("raw", 204, "body-raw_Half_Match", uploadFileId, null, null));
|
||||
MvcResult mockServerResult = this.requestPostWithOkAndReturn(ADD, mockServerRequest);
|
||||
ApiDefinitionMock definitionMock = getResultData(mockServerResult, ApiDefinitionMock.class);
|
||||
mockServerTestService.assertAddApiDefinitionMock(mockServerRequest, mockServerRequest.getMockMatchRule(), definitionMock.getId());
|
||||
mockList.add(definitionMock);
|
||||
}
|
||||
|
||||
API_MOCK_MAP.put(apiDefinition, mockList);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getFileMD5(byte[] bytes) {
|
||||
try {
|
||||
MessageDigest digest = MessageDigest.getInstance("MD5");
|
||||
digest.update(bytes, 0, bytes.length);
|
||||
BigInteger bigInt = new BigInteger(1, digest.digest());
|
||||
return bigInt.toString(16);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import io.metersphere.api.dto.assertion.MsAssertionConfig;
|
|||
import io.metersphere.api.dto.debug.ModuleCreateRequest;
|
||||
import io.metersphere.api.dto.definition.ApiDefinitionAddRequest;
|
||||
import io.metersphere.api.dto.definition.ApiTestCaseAddRequest;
|
||||
import io.metersphere.api.dto.definition.HttpResponse;
|
||||
import io.metersphere.api.dto.request.http.Header;
|
||||
import io.metersphere.api.dto.request.http.MsHTTPElement;
|
||||
import io.metersphere.api.dto.request.http.QueryParam;
|
||||
|
@ -57,7 +58,6 @@ import io.metersphere.system.controller.handler.ResultHolder;
|
|||
import io.metersphere.system.domain.Plugin;
|
||||
import io.metersphere.system.domain.Schedule;
|
||||
import io.metersphere.system.dto.request.PluginUpdateRequest;
|
||||
import io.metersphere.system.dto.sdk.BaseTreeNode;
|
||||
import io.metersphere.system.dto.sdk.request.PosRequest;
|
||||
import io.metersphere.system.log.constants.OperationLogType;
|
||||
import io.metersphere.system.mapper.ScheduleMapper;
|
||||
|
@ -68,6 +68,7 @@ import io.metersphere.system.utils.CheckLogModel;
|
|||
import io.metersphere.system.utils.Pager;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
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;
|
||||
|
@ -75,7 +76,6 @@ import org.springframework.http.MediaType;
|
|||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.ResultMatcher;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
|
@ -528,7 +528,8 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
queryParam2.setValue("bbb2");
|
||||
msHttpElement.setQuery(List.of(queryParam1, queryParam2));
|
||||
apiDefinitionAddRequest.setRequest(getMsElementParam(msHttpElement));
|
||||
apiDefinitionAddRequest.setResponse("{}");
|
||||
HttpResponse httpResponse = new HttpResponse();
|
||||
apiDefinitionAddRequest.setResponse(Collections.singletonList(httpResponse));
|
||||
apiDefinition = apiDefinitionService.create(apiDefinitionAddRequest, "admin");
|
||||
|
||||
ApiTestCaseAddRequest apiTestCaseAddRequest = new ApiTestCaseAddRequest();
|
||||
|
|
|
@ -4,6 +4,7 @@ import io.metersphere.api.dto.ApiFile;
|
|||
import io.metersphere.api.dto.ApiParamConfig;
|
||||
import io.metersphere.api.dto.assertion.MsAssertionConfig;
|
||||
import io.metersphere.api.dto.definition.HttpResponse;
|
||||
import io.metersphere.api.dto.definition.ResponseBody;
|
||||
import io.metersphere.api.dto.request.MsCommonElement;
|
||||
import io.metersphere.api.dto.request.http.*;
|
||||
import io.metersphere.api.dto.request.http.body.*;
|
||||
|
@ -475,24 +476,68 @@ public class MsHTTPElementTest {
|
|||
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.setFormValues(List.of(formDataKV));
|
||||
Body body = new Body();
|
||||
body.setBodyType(Body.BodyType.FORM_DATA.name());
|
||||
ResponseBody body = new ResponseBody();
|
||||
body.setBodyType(Body.BodyType.RAW.name());
|
||||
httpResponse.setBody(body);
|
||||
|
||||
httpResponses.add(httpResponse);
|
||||
return httpResponses;
|
||||
}
|
||||
|
||||
public static List<HttpResponse> get2MsHttpResponse(String returnPrefix) {
|
||||
List<HttpResponse> httpResponses = new ArrayList<>();
|
||||
HttpResponse http1Response = new HttpResponse();
|
||||
http1Response.setName("Response1");
|
||||
http1Response.setStatusCode("222");
|
||||
http1Response.setDefaultFlag(true);
|
||||
http1Response.setHeaders(new ArrayList<>() {{
|
||||
this.add(new Header() {{
|
||||
this.setEnable(false);
|
||||
this.setValue("valueA1");
|
||||
this.setKey("keyA1");
|
||||
this.setDescription("descA1");
|
||||
}});
|
||||
this.add(new Header() {{
|
||||
this.setEnable(true);
|
||||
this.setValue("headerDefaultValue");
|
||||
this.setKey("headerDefault");
|
||||
this.setDescription("headerDefaultDescA2");
|
||||
}});
|
||||
}});
|
||||
ResponseBody body1 = new ResponseBody();
|
||||
body1.setBodyType(Body.BodyType.RAW.name());
|
||||
body1.setRawBody(new RawBody() {{
|
||||
this.setValue(returnPrefix + "___responseDefault");
|
||||
}});
|
||||
http1Response.setBody(body1);
|
||||
httpResponses.add(http1Response);
|
||||
|
||||
HttpResponse http2Response = new HttpResponse();
|
||||
http2Response.setName("Response2");
|
||||
http2Response.setStatusCode("222");
|
||||
http2Response.setDefaultFlag(false);
|
||||
http2Response.setHeaders(new ArrayList<>() {{
|
||||
this.add(new Header() {{
|
||||
this.setEnable(false);
|
||||
this.setValue("valueB1");
|
||||
this.setKey("keyB1");
|
||||
this.setDescription("descB1");
|
||||
}});
|
||||
this.add(new Header() {{
|
||||
this.setEnable(true);
|
||||
this.setValue("valueB2");
|
||||
this.setKey("keyB2");
|
||||
this.setDescription("descB2");
|
||||
}});
|
||||
}});
|
||||
ResponseBody body2 = new ResponseBody();
|
||||
body2.setBodyType(Body.BodyType.RAW.name());
|
||||
body2.setRawBody(new RawBody() {{
|
||||
this.setValue(returnPrefix + "___response2");
|
||||
}});
|
||||
http2Response.setBody(body2);
|
||||
|
||||
httpResponses.add(http2Response);
|
||||
return httpResponses;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,360 @@
|
|||
package io.metersphere.api.service;
|
||||
|
||||
import io.metersphere.api.domain.ApiDefinitionBlob;
|
||||
import io.metersphere.api.domain.ApiDefinitionMock;
|
||||
import io.metersphere.api.domain.ApiDefinitionMockConfig;
|
||||
import io.metersphere.api.domain.ApiFileResource;
|
||||
import io.metersphere.api.dto.definition.HttpResponse;
|
||||
import io.metersphere.api.dto.definition.ResponseBinaryBody;
|
||||
import io.metersphere.api.dto.definition.ResponseBody;
|
||||
import io.metersphere.api.dto.mockserver.*;
|
||||
import io.metersphere.api.dto.request.http.Header;
|
||||
import io.metersphere.api.dto.request.http.body.Body;
|
||||
import io.metersphere.api.dto.request.http.body.JsonBody;
|
||||
import io.metersphere.api.dto.request.http.body.RawBody;
|
||||
import io.metersphere.api.dto.request.http.body.XmlBody;
|
||||
import io.metersphere.api.mapper.ApiDefinitionMockConfigMapper;
|
||||
import io.metersphere.api.mapper.ApiDefinitionMockMapper;
|
||||
import io.metersphere.api.utils.ApiDataUtils;
|
||||
import io.metersphere.project.dto.filemanagement.FileInfo;
|
||||
import io.metersphere.project.service.FileAssociationService;
|
||||
import io.metersphere.sdk.constants.DefaultRepositoryDir;
|
||||
import io.metersphere.sdk.file.FileCenter;
|
||||
import io.metersphere.sdk.file.FileRequest;
|
||||
import io.metersphere.sdk.util.BeanUtils;
|
||||
import io.metersphere.sdk.util.CommonBeanFactory;
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
import io.metersphere.sdk.util.Translator;
|
||||
import io.metersphere.system.uid.IDGenerator;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
import org.testcontainers.shaded.org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static io.metersphere.api.service.BaseResourcePoolTestService.DEFAULT_PROJECT_ID;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@Service
|
||||
public class MockServerTestService {
|
||||
|
||||
@Resource
|
||||
private ApiDefinitionMockMapper apiDefinitionMockMapper;
|
||||
@Resource
|
||||
private ApiDefinitionMockConfigMapper apiDefinitionMockConfigMapper;
|
||||
|
||||
|
||||
public static MockMultipartFile getMockMultipartFile(String fileName) {
|
||||
return new MockMultipartFile(
|
||||
"file",
|
||||
fileName,
|
||||
MediaType.APPLICATION_OCTET_STREAM_VALUE,
|
||||
"Hello, World!".getBytes()
|
||||
);
|
||||
}
|
||||
|
||||
public static MockMultipartFile getMockMultipartFile(String fileName, String fileContent) {
|
||||
return new MockMultipartFile(
|
||||
"file",
|
||||
fileName,
|
||||
MediaType.APPLICATION_OCTET_STREAM_VALUE,
|
||||
fileContent.getBytes()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 校验上传的文件
|
||||
*
|
||||
* @param id
|
||||
* @param fileIds 全部的文件ID
|
||||
*/
|
||||
public static void assertUploadFile(String id, List<String> fileIds) throws Exception {
|
||||
if (fileIds != null) {
|
||||
ApiFileResourceService apiFileResourceService = CommonBeanFactory.getBean(ApiFileResourceService.class);
|
||||
// 验证文件的关联关系,以及是否存入对象存储
|
||||
List<ApiFileResource> apiFileResources = apiFileResourceService.getByResourceId(id);
|
||||
Assertions.assertEquals(apiFileResources.size(), fileIds.size());
|
||||
|
||||
String apiDefinitionDir = DefaultRepositoryDir.getApiDefinitionDir(DEFAULT_PROJECT_ID, id);
|
||||
FileRequest fileRequest = new FileRequest();
|
||||
if (!fileIds.isEmpty()) {
|
||||
for (ApiFileResource apiFileResource : apiFileResources) {
|
||||
Assertions.assertEquals(DEFAULT_PROJECT_ID, apiFileResource.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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验上传的文件
|
||||
*
|
||||
* @param id
|
||||
* @param fileIds 全部的文件ID
|
||||
*/
|
||||
public static void assertLinkFile(String id, List<String> fileIds) {
|
||||
FileAssociationService fileAssociationService = CommonBeanFactory.getBean(FileAssociationService.class);
|
||||
List<String> linkFileIds = fileAssociationService.getFiles(id)
|
||||
.stream()
|
||||
.map(FileInfo::getFileId)
|
||||
.toList();
|
||||
Assertions.assertEquals(fileIds, linkFileIds);
|
||||
}
|
||||
|
||||
public ApiDefinitionMock assertAddApiDefinitionMock(Object request, MockMatchRule mockMatchRule, String id) {
|
||||
ApiDefinitionMock apiDefinitionMock = apiDefinitionMockMapper.selectByPrimaryKey(id);
|
||||
ApiDefinitionMockConfig apiDefinitionMockConfig = apiDefinitionMockConfigMapper.selectByPrimaryKey(id);
|
||||
ApiDefinitionMock copyApiDefinitionMock = BeanUtils.copyBean(new ApiDefinitionMock(), apiDefinitionMock);
|
||||
BeanUtils.copyBean(copyApiDefinitionMock, request);
|
||||
Assertions.assertEquals(apiDefinitionMock, copyApiDefinitionMock);
|
||||
if (apiDefinitionMockConfig != null) {
|
||||
Assertions.assertEquals(mockMatchRule, ApiDataUtils.parseObject(new String(apiDefinitionMockConfig.getMatching()), MockMatchRule.class));
|
||||
}
|
||||
return apiDefinitionMock;
|
||||
}
|
||||
|
||||
public MockMatchRule genMockMatchRule(String valuePrefix, boolean hasQuery, boolean hasHeader, String bodyParamType, boolean matchAll) {
|
||||
MockMatchRule mockMatchRule = new MockMatchRule();
|
||||
|
||||
keyValueMatchRole restMatchRule = new keyValueMatchRole();
|
||||
restMatchRule.setMatchAll(matchAll);
|
||||
restMatchRule.setMatchRules(new ArrayList<>() {{
|
||||
this.add(new KeyValueInfo() {{
|
||||
this.setKey("param1");
|
||||
this.setValue(valuePrefix + "__query-" + hasQuery + "_header-" + hasHeader);
|
||||
}});
|
||||
this.add(new KeyValueInfo() {{
|
||||
this.setKey("param2");
|
||||
this.setValue(valuePrefix + "-Param2");
|
||||
}});
|
||||
}});
|
||||
mockMatchRule.setRest(restMatchRule);
|
||||
|
||||
if (hasQuery) {
|
||||
keyValueMatchRole queryMatchRule = new keyValueMatchRole();
|
||||
queryMatchRule.setMatchAll(matchAll);
|
||||
queryMatchRule.setMatchRules(new ArrayList<>() {{
|
||||
this.add(new KeyValueInfo() {{
|
||||
this.setKey("queryParam1");
|
||||
this.setValue(valuePrefix + "_queryParam1Value");
|
||||
}});
|
||||
this.add(new KeyValueInfo() {{
|
||||
this.setKey("queryParam2");
|
||||
this.setValue(valuePrefix + "_queryParam2Value");
|
||||
}});
|
||||
this.add(new KeyValueInfo() {{
|
||||
this.setKey("queryParam3");
|
||||
this.setValue(valuePrefix + "_queryParam3Value");
|
||||
}});
|
||||
}});
|
||||
mockMatchRule.setQuery(queryMatchRule);
|
||||
}
|
||||
|
||||
if (hasHeader) {
|
||||
keyValueMatchRole headerMatchRule = new keyValueMatchRole();
|
||||
headerMatchRule.setMatchAll(matchAll);
|
||||
headerMatchRule.setMatchRules(new ArrayList<>() {{
|
||||
this.add(new KeyValueInfo() {{
|
||||
this.setKey("headerA");
|
||||
this.setValue(valuePrefix + "-header-1");
|
||||
}});
|
||||
this.add(new KeyValueInfo() {{
|
||||
this.setKey("headerB");
|
||||
this.setValue(valuePrefix + "-header-2");
|
||||
}});
|
||||
this.add(new KeyValueInfo() {{
|
||||
this.setKey("headerC");
|
||||
this.setValue(valuePrefix + "-header-3");
|
||||
}});
|
||||
}});
|
||||
mockMatchRule.setHeader(headerMatchRule);
|
||||
}
|
||||
|
||||
if (StringUtils.equalsIgnoreCase(bodyParamType, "kv")) {
|
||||
mockMatchRule.setBody(new BodyParamMatchRole() {{
|
||||
this.setParamType(Body.BodyType.FORM_DATA.name());
|
||||
this.setFormDataMatch(new keyValueMatchRole() {{
|
||||
this.setMatchAll(matchAll);
|
||||
this.setMatchRules(new ArrayList<>() {{
|
||||
this.add(new KeyValueInfo() {{
|
||||
this.setKey("bodyKvParam1");
|
||||
this.setValue(valuePrefix + "_bodyKvParam1");
|
||||
}});
|
||||
this.add(new KeyValueInfo() {{
|
||||
this.setKey("bodyParam2");
|
||||
this.setValue(valuePrefix + "_bodyKvParam2");
|
||||
}});
|
||||
this.add(new KeyValueInfo() {{
|
||||
this.setKey("bodyParam3");
|
||||
this.setValue(valuePrefix + "_bodyKvParam3");
|
||||
}});
|
||||
}});
|
||||
}});
|
||||
}});
|
||||
} else if (StringUtils.equalsIgnoreCase(bodyParamType, "raw")) {
|
||||
mockMatchRule.setBody(new BodyParamMatchRole() {{
|
||||
this.setParamType(Body.BodyType.RAW.name());
|
||||
this.setRaw(valuePrefix + "_inputRawBody");
|
||||
}});
|
||||
} else if (StringUtils.equalsIgnoreCase(bodyParamType, "json")) {
|
||||
mockMatchRule.setBody(new BodyParamMatchRole() {{
|
||||
this.setParamType(Body.BodyType.JSON.name());
|
||||
this.setRaw("{\"inputAge\":123}");
|
||||
}});
|
||||
} else if (StringUtils.equalsIgnoreCase(bodyParamType, "xml")) {
|
||||
mockMatchRule.setBody(new BodyParamMatchRole() {{
|
||||
this.setParamType(Body.BodyType.XML.name());
|
||||
this.setRaw("<xml>input123</xml>");
|
||||
}});
|
||||
}
|
||||
return mockMatchRule;
|
||||
}
|
||||
|
||||
public MockResponse genMockResponse(String returnType, int status, String valueKeyWord, String fileId, String fileName, ApiDefinitionBlob apiDefinitionBlob) {
|
||||
MockResponse mockResponse = new MockResponse();
|
||||
mockResponse.setStatusCode(status);
|
||||
if (apiDefinitionBlob != null) {
|
||||
mockResponse.setUseApiResponse(true);
|
||||
List<HttpResponse> msHttpResponseList = JSON.parseArray(new String(apiDefinitionBlob.getResponse()), HttpResponse.class);
|
||||
msHttpResponseList.forEach(item -> {
|
||||
if (!item.isDefaultFlag()) {
|
||||
//特意使用非默认的响应
|
||||
mockResponse.setApiResponseId(item.getId());
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ResponseBody body = new ResponseBody();
|
||||
switch (returnType) {
|
||||
case "file":
|
||||
body.setBodyType(Body.BodyType.BINARY.name());
|
||||
body.setBinaryBody(new ResponseBinaryBody() {{
|
||||
this.setSendAsBody(false);
|
||||
this.setFileId(fileId);
|
||||
this.setFileName(fileName);
|
||||
}});
|
||||
break;
|
||||
case "file-body":
|
||||
body.setBodyType(Body.BodyType.BINARY.name());
|
||||
body.setBinaryBody(new ResponseBinaryBody() {{
|
||||
this.setSendAsBody(false);
|
||||
this.setFileId(fileId);
|
||||
this.setFileName(fileName);
|
||||
}});
|
||||
break;
|
||||
case "json":
|
||||
body.setBodyType(Body.BodyType.JSON.name());
|
||||
body.setJsonBody(new JsonBody() {{
|
||||
this.setJsonValue("{\"inputAge\":123, \"testKeyWord\":\"" + valueKeyWord + "\"}");
|
||||
}});
|
||||
break;
|
||||
case "xml":
|
||||
body.setBodyType(Body.BodyType.XML.name());
|
||||
body.setXmlBody(new XmlBody() {{
|
||||
this.setValue("<xml>" + valueKeyWord + "</xml>");
|
||||
}});
|
||||
break;
|
||||
case "raw":
|
||||
body.setBodyType(Body.BodyType.RAW.name());
|
||||
body.setRawBody(new RawBody() {{
|
||||
this.setValue("Raw body content:" + valueKeyWord);
|
||||
}});
|
||||
break;
|
||||
}
|
||||
mockResponse.setBody(body);
|
||||
}
|
||||
|
||||
List<Header> headers = new ArrayList<>() {{
|
||||
this.add(new Header() {{
|
||||
this.setKey("rspHeaderA");
|
||||
this.setValue("header-1");
|
||||
}});
|
||||
this.add(new Header() {{
|
||||
this.setKey("rspHeaderB");
|
||||
this.setValue("header-2");
|
||||
this.setEnable(false);
|
||||
}});
|
||||
this.add(new Header() {{
|
||||
this.setKey("rspHeaderC");
|
||||
this.setValue("header-3");
|
||||
}});
|
||||
}};
|
||||
mockResponse.setHeaders(headers);
|
||||
return mockResponse;
|
||||
}
|
||||
|
||||
public MockHttpServletRequestBuilder getRequestBuilder(String method, String url) {
|
||||
MockHttpServletRequestBuilder requestBuilder = null;
|
||||
if (StringUtils.equalsIgnoreCase(method, "get")) {
|
||||
requestBuilder = MockMvcRequestBuilders.get(url);
|
||||
} else if (StringUtils.equalsIgnoreCase(method, "post")) {
|
||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
||||
} else if (StringUtils.equalsIgnoreCase(method, "put")) {
|
||||
requestBuilder = MockMvcRequestBuilders.put(url);
|
||||
} else if (StringUtils.equalsIgnoreCase(method, "delete")) {
|
||||
requestBuilder = MockMvcRequestBuilders.delete(url);
|
||||
} else if (StringUtils.equalsIgnoreCase(method, "patch")) {
|
||||
requestBuilder = MockMvcRequestBuilders.patch(url);
|
||||
} else if (StringUtils.equalsIgnoreCase(method, "head")) {
|
||||
requestBuilder = MockMvcRequestBuilders.head(url);
|
||||
} else if (StringUtils.equalsIgnoreCase(method, "options")) {
|
||||
requestBuilder = MockMvcRequestBuilders.options(url);
|
||||
} else if (StringUtils.equalsIgnoreCase(method, "trace")) {
|
||||
requestBuilder = MockMvcRequestBuilders.request(HttpMethod.TRACE, url);
|
||||
}
|
||||
return requestBuilder;
|
||||
}
|
||||
|
||||
@Resource
|
||||
private MockMvc mockMvc;
|
||||
|
||||
public void testNoMatchMockConfig(String method, String url, String apiDefinitionPath) throws Exception {
|
||||
|
||||
url = StringUtils.replace(url, "{param1}", "param1");
|
||||
url = StringUtils.replace(url, "{param2}", "param2");
|
||||
MockHttpServletRequestBuilder requestBuilder;
|
||||
if (StringUtils.equalsAnyIgnoreCase(method, "get", "delete")) {
|
||||
requestBuilder = getRequestBuilder(method, url + IDGenerator.nextStr());
|
||||
Assertions.assertNotNull(requestBuilder);
|
||||
} else {
|
||||
requestBuilder = getRequestBuilder(method, url);
|
||||
}
|
||||
ResultActions action = mockMvc.perform(requestBuilder);
|
||||
MvcResult mockResult = action.andReturn();
|
||||
String returnStr = mockResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||
Assertions.assertEquals(returnStr, apiDefinitionPath + "___responseDefault");
|
||||
Assertions.assertEquals(mockResult.getResponse().getStatus(), 222);
|
||||
}
|
||||
|
||||
public void testNoMatchApi() throws Exception {
|
||||
String url = "/mock-server/100001/" + "error" + "/test/error";
|
||||
this.testApiNoMockConfigAndNoResponse(url);
|
||||
}
|
||||
|
||||
public void testApiNoMockConfigAndNoResponse(String url) throws Exception {
|
||||
MockHttpServletRequestBuilder requestBuilder = getRequestBuilder("get", url);
|
||||
ResultActions action = mockMvc.perform(requestBuilder);
|
||||
action.andExpect(status().isNotFound());
|
||||
MvcResult mockResult = action.andReturn();
|
||||
String returnStr = mockResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||
Assertions.assertEquals(returnStr, Translator.get("mock_warning"));
|
||||
}
|
||||
}
|
|
@ -26,13 +26,13 @@ import io.metersphere.system.utils.CheckLogModel;
|
|||
import io.metersphere.system.utils.Pager;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
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.http.MediaType;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
|
@ -203,40 +203,6 @@ public class FileRepositoryControllerTest extends BaseTest {
|
|||
Assertions.assertEquals(response.getToken(), GITEA_TOKEN);
|
||||
Assertions.assertEquals(response.getUrl(), GITEA_URL);
|
||||
|
||||
//测试创建gitee的
|
||||
String giteeUrl = "https://gitee.com/testformeterspere/gitee-test.git";
|
||||
String giteeUserName = "testformetersphere";
|
||||
String giteeToken = "4548d369bb595738d726512742e4478f";
|
||||
createRequest = new FileRepositoryCreateRequest();
|
||||
createRequest.setProjectId(project.getId());
|
||||
createRequest.setPlatform(ModuleConstants.NODE_TYPE_GITEE);
|
||||
createRequest.setUrl(giteeUrl);
|
||||
createRequest.setUserName(giteeUserName);
|
||||
createRequest.setToken(giteeToken);
|
||||
createRequest.setName("GITEE存储库");
|
||||
|
||||
int tryCount = 0;
|
||||
while (true) {
|
||||
//github连接gitee有时会连不到,这里重试10次。
|
||||
result = this.requestPost(FileManagementRequestUtils.URL_FILE_REPOSITORY_CREATE, createRequest).andReturn();
|
||||
if (result.getResponse().getStatus() == 200) {
|
||||
break;
|
||||
} else {
|
||||
tryCount++;
|
||||
if (tryCount > 10) {
|
||||
throw new Exception("无法创建gitee存储库");
|
||||
} else {
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
returnStr = result.getResponse().getContentAsString();
|
||||
rh = JSON.parseObject(returnStr, ResultHolder.class);
|
||||
this.checkFileRepository(rh.getData().toString(), createRequest.getProjectId(), createRequest.getName(), createRequest.getPlatform(), createRequest.getUrl(), createRequest.getToken(), createRequest.getUserName());
|
||||
LOG_CHECK_LIST.add(
|
||||
new CheckLogModel(rh.getData().toString(), OperationLogType.ADD, FileManagementRequestUtils.URL_FILE_REPOSITORY_CREATE)
|
||||
);
|
||||
|
||||
//参数测试: 没有url
|
||||
createRequest = new FileRepositoryCreateRequest();
|
||||
|
@ -283,12 +249,13 @@ public class FileRepositoryControllerTest extends BaseTest {
|
|||
createRequest.setToken(GITEA_TOKEN);
|
||||
createRequest.setName("GITEA存储库");
|
||||
this.requestPost(FileManagementRequestUtils.URL_FILE_REPOSITORY_CREATE, createRequest).andExpect(status().is5xxServerError());
|
||||
|
||||
//报错测试: gitee仓库,不填写用户名
|
||||
createRequest = new FileRepositoryCreateRequest();
|
||||
createRequest.setProjectId(project.getId());
|
||||
createRequest.setPlatform(ModuleConstants.NODE_TYPE_GITEE);
|
||||
createRequest.setUrl(giteeUrl);
|
||||
createRequest.setToken(giteeToken);
|
||||
createRequest.setUrl("gitee/test/url");
|
||||
createRequest.setToken("gitee-token");
|
||||
createRequest.setName("Gitee无用户名存储库");
|
||||
this.requestPost(FileManagementRequestUtils.URL_FILE_REPOSITORY_CREATE, createRequest).andExpect(status().is5xxServerError());
|
||||
|
||||
|
|
Loading…
Reference in New Issue