fix(接口测试): 接口与用例对比接口
--task=1015861 --user=陈建星 【接口测试】接口用例支持同步更新接口变更-是否与定义不一致查询接口 https://www.tapd.cn/55049933/s/1557706
This commit is contained in:
parent
4033ffea7a
commit
f0a3cceb44
|
@ -17,10 +17,9 @@ import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.regex.Matcher;
|
||||||
import java.util.List;
|
import java.util.regex.Pattern;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class XMLUtils {
|
public class XMLUtils {
|
||||||
public static final boolean IS_TRANS = false;
|
public static final boolean IS_TRANS = false;
|
||||||
|
@ -142,4 +141,36 @@ public class XMLUtils {
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归清空元素的文本内容
|
||||||
|
*/
|
||||||
|
public static void clearElementText(Element element) {
|
||||||
|
// 清空当前元素的文本内容
|
||||||
|
element.setText(StringUtils.EMPTY);
|
||||||
|
|
||||||
|
// 递归处理子元素
|
||||||
|
Iterator<Element> iterator = element.elementIterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
clearElementText(iterator.next());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用正则清空元素的文本内容
|
||||||
|
*/
|
||||||
|
public static String clearElementText(String text) {
|
||||||
|
// 正则表达式匹配 XML 标签中的内容
|
||||||
|
String regex = "(<[^<>]+>)([^<>]*)(</[^<>]+>)";
|
||||||
|
Pattern pattern = Pattern.compile(regex);
|
||||||
|
Matcher matcher = pattern.matcher(text);
|
||||||
|
|
||||||
|
// 替换内容为空字符串
|
||||||
|
StringBuffer result = new StringBuffer();
|
||||||
|
while (matcher.find()) {
|
||||||
|
matcher.appendReplacement(result, matcher.group(1) + StringUtils.EMPTY + matcher.group(3));
|
||||||
|
}
|
||||||
|
matcher.appendTail(result);
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import com.github.pagehelper.Page;
|
||||||
import com.github.pagehelper.PageHelper;
|
import com.github.pagehelper.PageHelper;
|
||||||
import io.metersphere.api.constants.ApiConstants;
|
import io.metersphere.api.constants.ApiConstants;
|
||||||
import io.metersphere.api.domain.ApiTestCase;
|
import io.metersphere.api.domain.ApiTestCase;
|
||||||
|
import io.metersphere.api.dto.ApiCaseCompareData;
|
||||||
import io.metersphere.api.dto.ReferenceDTO;
|
import io.metersphere.api.dto.ReferenceDTO;
|
||||||
import io.metersphere.api.dto.ReferenceRequest;
|
import io.metersphere.api.dto.ReferenceRequest;
|
||||||
import io.metersphere.api.dto.definition.*;
|
import io.metersphere.api.dto.definition.*;
|
||||||
|
@ -308,4 +309,12 @@ public class ApiTestCaseController {
|
||||||
public void clearApiChange(@PathVariable String id) {
|
public void clearApiChange(@PathVariable String id) {
|
||||||
apiTestCaseService.clearApiChange(id);
|
apiTestCaseService.clearApiChange(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/api/compare/{id}")
|
||||||
|
@Operation(summary = "与接口定义对比")
|
||||||
|
@RequiresPermissions(value = PermissionConstants.PROJECT_API_DEFINITION_CASE_READ)
|
||||||
|
@CheckOwner(resourceId = "#id", resourceType = "api_test_case")
|
||||||
|
public ApiCaseCompareData getApiCompareData(@PathVariable String id) {
|
||||||
|
return apiTestCaseService.getApiCompareData(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
package io.metersphere.api.dto;
|
||||||
|
|
||||||
|
import io.metersphere.plugin.api.spi.MsTestElement;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: jianxing
|
||||||
|
* @CreateTime: 2024-08-02 17:49
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ApiCaseCompareData {
|
||||||
|
private MsTestElement apiRequest;
|
||||||
|
private MsTestElement caseRequest;
|
||||||
|
}
|
|
@ -16,8 +16,6 @@ import org.apache.jmeter.protocol.http.util.HTTPFileArg;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author: jianxing
|
* @Author: jianxing
|
||||||
|
@ -80,29 +78,6 @@ public abstract class MsBodyConverter<T> {
|
||||||
return fileArg;
|
return fileArg;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 将文本中的 @xxx 转换成 ${__Mock(@xxx)}
|
|
||||||
*
|
|
||||||
* @param text
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
protected String parseTextMock(String text) {
|
|
||||||
String pattern = "[\"\\s:]@[a-zA-Z\\\\(|,'-\\\\d ]*[a-zA-Z)-9),\\\\\"]";
|
|
||||||
Pattern regex = Pattern.compile(pattern);
|
|
||||||
Matcher matcher = regex.matcher(text);
|
|
||||||
while (matcher.find()) {
|
|
||||||
//取出group的最后一个字符 主要是防止 @string|number 和 @string 这种情况
|
|
||||||
//如果是 “ 或者, 结尾的 需要截取
|
|
||||||
String group = matcher.group();
|
|
||||||
if (group.endsWith(",") || group.endsWith("\"")) {
|
|
||||||
group = group.substring(0, group.length() - 1);
|
|
||||||
}
|
|
||||||
// 去掉第一个字符,因为第一个字符是 " : 或者空格
|
|
||||||
group = group.substring(1, group.length());
|
|
||||||
text = text.replace(group, StringUtils.join("${__Mock(", group.replace(",", "\\,"), ")}"));
|
|
||||||
}
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* 处理raw格式参数
|
* 处理raw格式参数
|
||||||
* 包含了 json 等格式
|
* 包含了 json 等格式
|
||||||
|
|
|
@ -60,6 +60,30 @@ public class MsJsonBodyConverter extends MsBodyConverter<JsonBody> {
|
||||||
return jsonStr;
|
return jsonStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将文本中的 @xxx 转换成 ${__Mock(@xxx)}
|
||||||
|
*
|
||||||
|
* @param text
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected String parseTextMock(String text) {
|
||||||
|
String pattern = "[\"\\s:]@[a-zA-Z\\\\(|,'-\\\\d ]*[a-zA-Z)-9),\\\\\"]";
|
||||||
|
Pattern regex = Pattern.compile(pattern);
|
||||||
|
Matcher matcher = regex.matcher(text);
|
||||||
|
while (matcher.find()) {
|
||||||
|
//取出group的最后一个字符 主要是防止 @string|number 和 @string 这种情况
|
||||||
|
//如果是 “ 或者, 结尾的 需要截取
|
||||||
|
String group = matcher.group();
|
||||||
|
if (group.endsWith(",") || group.endsWith("\"")) {
|
||||||
|
group = group.substring(0, group.length() - 1);
|
||||||
|
}
|
||||||
|
// 去掉第一个字符,因为第一个字符是 " : 或者空格
|
||||||
|
group = group.substring(1, group.length());
|
||||||
|
text = text.replace(group, StringUtils.join("${__Mock(", group.replace(",", "\\,"), ")}"));
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
private void parseMock(List list) {
|
private void parseMock(List list) {
|
||||||
Map<Integer, String> replaceDataMap = new HashMap<>();
|
Map<Integer, String> replaceDataMap = new HashMap<>();
|
||||||
for (int index = 0; index < list.size(); index++) {
|
for (int index = 0; index < list.size(); index++) {
|
||||||
|
|
|
@ -81,11 +81,11 @@ public class ApiReportSendNoticeService {
|
||||||
ApiExecuteResourceType.API_SCENARIO.name(), ApiExecuteResourceType.TEST_PLAN_API_SCENARIO.name(), ApiExecuteResourceType.PLAN_RUN_API_SCENARIO.name())) {
|
ApiExecuteResourceType.API_SCENARIO.name(), ApiExecuteResourceType.TEST_PLAN_API_SCENARIO.name(), ApiExecuteResourceType.PLAN_RUN_API_SCENARIO.name())) {
|
||||||
ApiScenario scenario = null;
|
ApiScenario scenario = null;
|
||||||
switch (ApiExecuteResourceType.valueOf(noticeDTO.getResourceType())) {
|
switch (ApiExecuteResourceType.valueOf(noticeDTO.getResourceType())) {
|
||||||
case ApiExecuteResourceType.API_SCENARIO ->
|
case API_SCENARIO ->
|
||||||
scenario = apiScenarioMapper.selectByPrimaryKey(noticeDTO.getResourceId());
|
scenario = apiScenarioMapper.selectByPrimaryKey(noticeDTO.getResourceId());
|
||||||
case ApiExecuteResourceType.TEST_PLAN_API_SCENARIO ->
|
case TEST_PLAN_API_SCENARIO ->
|
||||||
scenario = extApiScenarioMapper.getScenarioByResourceId(noticeDTO.getResourceId());
|
scenario = extApiScenarioMapper.getScenarioByResourceId(noticeDTO.getResourceId());
|
||||||
case ApiExecuteResourceType.PLAN_RUN_API_SCENARIO ->
|
case PLAN_RUN_API_SCENARIO ->
|
||||||
scenario = extApiScenarioMapper.getScenarioByReportId(noticeDTO.getResourceId());
|
scenario = extApiScenarioMapper.getScenarioByReportId(noticeDTO.getResourceId());
|
||||||
default -> {
|
default -> {
|
||||||
}
|
}
|
||||||
|
@ -109,11 +109,11 @@ public class ApiReportSendNoticeService {
|
||||||
ApiExecuteResourceType.API_CASE.name(), ApiExecuteResourceType.TEST_PLAN_API_CASE.name(), ApiExecuteResourceType.PLAN_RUN_API_CASE.name())) {
|
ApiExecuteResourceType.API_CASE.name(), ApiExecuteResourceType.TEST_PLAN_API_CASE.name(), ApiExecuteResourceType.PLAN_RUN_API_CASE.name())) {
|
||||||
ApiTestCase testCase = null;
|
ApiTestCase testCase = null;
|
||||||
switch (ApiExecuteResourceType.valueOf(noticeDTO.getResourceType())) {
|
switch (ApiExecuteResourceType.valueOf(noticeDTO.getResourceType())) {
|
||||||
case ApiExecuteResourceType.API_CASE ->
|
case API_CASE ->
|
||||||
testCase = apiTestCaseMapper.selectByPrimaryKey(noticeDTO.getResourceId());
|
testCase = apiTestCaseMapper.selectByPrimaryKey(noticeDTO.getResourceId());
|
||||||
case ApiExecuteResourceType.TEST_PLAN_API_CASE ->
|
case TEST_PLAN_API_CASE ->
|
||||||
testCase = extApiTestCaseMapper.getCaseByResourceId(noticeDTO.getResourceId());
|
testCase = extApiTestCaseMapper.getCaseByResourceId(noticeDTO.getResourceId());
|
||||||
case ApiExecuteResourceType.PLAN_RUN_API_CASE ->
|
case PLAN_RUN_API_CASE ->
|
||||||
testCase = extApiTestCaseMapper.getCaseByReportId(noticeDTO.getResourceId());
|
testCase = extApiTestCaseMapper.getCaseByReportId(noticeDTO.getResourceId());
|
||||||
default -> {
|
default -> {
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import io.metersphere.api.dto.debug.ApiFileResourceUpdateRequest;
|
||||||
import io.metersphere.api.dto.debug.ApiResourceRunRequest;
|
import io.metersphere.api.dto.debug.ApiResourceRunRequest;
|
||||||
import io.metersphere.api.dto.definition.*;
|
import io.metersphere.api.dto.definition.*;
|
||||||
import io.metersphere.api.dto.request.ApiTransferRequest;
|
import io.metersphere.api.dto.request.ApiTransferRequest;
|
||||||
|
import io.metersphere.api.dto.request.http.MsHTTPElement;
|
||||||
import io.metersphere.api.mapper.*;
|
import io.metersphere.api.mapper.*;
|
||||||
import io.metersphere.api.service.ApiCommonService;
|
import io.metersphere.api.service.ApiCommonService;
|
||||||
import io.metersphere.api.service.ApiExecuteService;
|
import io.metersphere.api.service.ApiExecuteService;
|
||||||
|
@ -241,14 +242,14 @@ public class ApiTestCaseService extends MoveNodeService {
|
||||||
example.createCriteria().andCaseIdEqualTo(id).andUserIdEqualTo(userId);
|
example.createCriteria().andCaseIdEqualTo(id).andUserIdEqualTo(userId);
|
||||||
List<ApiTestCaseFollower> followers = apiTestCaseFollowerMapper.selectByExample(example);
|
List<ApiTestCaseFollower> followers = apiTestCaseFollowerMapper.selectByExample(example);
|
||||||
apiTestCaseDTO.setFollow(CollectionUtils.isNotEmpty(followers));
|
apiTestCaseDTO.setFollow(CollectionUtils.isNotEmpty(followers));
|
||||||
AbstractMsTestElement msTestElement = ApiDataUtils.parseObject(new String(testCaseBlob.getRequest()), AbstractMsTestElement.class);
|
AbstractMsTestElement msTestElement = getTestElement(testCaseBlob);
|
||||||
apiCommonService.setLinkFileInfo(id, msTestElement);
|
apiCommonService.setLinkFileInfo(id, msTestElement);
|
||||||
apiCommonService.setEnableCommonScriptProcessorInfo(msTestElement);
|
apiCommonService.setEnableCommonScriptProcessorInfo(msTestElement);
|
||||||
apiCommonService.setApiDefinitionExecuteInfo(msTestElement, apiDefinition);
|
apiCommonService.setApiDefinitionExecuteInfo(msTestElement, apiDefinition);
|
||||||
apiTestCaseDTO.setRequest(msTestElement);
|
apiTestCaseDTO.setRequest(msTestElement);
|
||||||
|
|
||||||
ApiDefinitionBlob apiDefinitionBlob = apiDefinitionBlobMapper.selectByPrimaryKey(apiDefinition.getId());
|
ApiDefinitionBlob apiDefinitionBlob = apiDefinitionBlobMapper.selectByPrimaryKey(apiDefinition.getId());
|
||||||
AbstractMsTestElement apiMsTestElement = ApiDataUtils.parseObject(new String(apiDefinitionBlob.getRequest()), AbstractMsTestElement.class);
|
AbstractMsTestElement apiMsTestElement = getApiMsTestElement(apiDefinitionBlob);
|
||||||
apiTestCaseDTO.setInconsistentWithApi(HttpRequestParamDiffUtils.isRequestParamDiff(apiMsTestElement, msTestElement));
|
apiTestCaseDTO.setInconsistentWithApi(HttpRequestParamDiffUtils.isRequestParamDiff(apiMsTestElement, msTestElement));
|
||||||
return apiTestCaseDTO;
|
return apiTestCaseDTO;
|
||||||
}
|
}
|
||||||
|
@ -649,7 +650,7 @@ public class ApiTestCaseService extends MoveNodeService {
|
||||||
if (apiTestCaseBlob == null) {
|
if (apiTestCaseBlob == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
AbstractMsTestElement msTestElement = ApiDataUtils.parseObject(new String(apiTestCaseBlob.getRequest()), AbstractMsTestElement.class);
|
AbstractMsTestElement msTestElement = getTestElement(apiTestCaseBlob);
|
||||||
// 获取接口中需要更新的文件
|
// 获取接口中需要更新的文件
|
||||||
List<ApiFile> updateFiles = apiCommonService.getApiFilesByFileId(originFileAssociation.getFileId(), msTestElement);
|
List<ApiFile> updateFiles = apiCommonService.getApiFilesByFileId(originFileAssociation.getFileId(), msTestElement);
|
||||||
// 替换文件的Id和name
|
// 替换文件的Id和name
|
||||||
|
@ -695,7 +696,7 @@ public class ApiTestCaseService extends MoveNodeService {
|
||||||
ApiTestCaseBlob apiTestCaseBlob = apiTestCaseBlobMapper.selectByPrimaryKey(id);
|
ApiTestCaseBlob apiTestCaseBlob = apiTestCaseBlobMapper.selectByPrimaryKey(id);
|
||||||
|
|
||||||
ApiResourceRunRequest runRequest = new ApiResourceRunRequest();
|
ApiResourceRunRequest runRequest = new ApiResourceRunRequest();
|
||||||
runRequest.setTestElement(ApiDataUtils.parseObject(new String(apiTestCaseBlob.getRequest()), AbstractMsTestElement.class));
|
runRequest.setTestElement(getTestElement(apiTestCaseBlob));
|
||||||
|
|
||||||
return executeRun(runRequest, apiTestCase, reportId, userId);
|
return executeRun(runRequest, apiTestCase, reportId, userId);
|
||||||
}
|
}
|
||||||
|
@ -784,7 +785,7 @@ public class ApiTestCaseService extends MoveNodeService {
|
||||||
apiParamConfig.setRetryOnFail(request.getRunModeConfig().getRetryOnFail());
|
apiParamConfig.setRetryOnFail(request.getRunModeConfig().getRetryOnFail());
|
||||||
apiParamConfig.setRetryConfig(request.getRunModeConfig().getRetryConfig());
|
apiParamConfig.setRetryConfig(request.getRunModeConfig().getRetryConfig());
|
||||||
|
|
||||||
AbstractMsTestElement msTestElement = ApiDataUtils.parseObject(new String(apiTestCaseBlob.getRequest()), AbstractMsTestElement.class);
|
AbstractMsTestElement msTestElement = getTestElement(apiTestCaseBlob);
|
||||||
// 设置 method 等信息
|
// 设置 method 等信息
|
||||||
apiCommonService.setApiDefinitionExecuteInfo(msTestElement, BeanUtils.copyBean(new ApiDefinitionExecuteInfo(), apiDefinition));
|
apiCommonService.setApiDefinitionExecuteInfo(msTestElement, BeanUtils.copyBean(new ApiDefinitionExecuteInfo(), apiDefinition));
|
||||||
|
|
||||||
|
@ -951,4 +952,30 @@ public class ApiTestCaseService extends MoveNodeService {
|
||||||
apiTestCase.setApiChange(false);
|
apiTestCase.setApiChange(false);
|
||||||
apiTestCaseMapper.updateByPrimaryKeySelective(apiTestCase);
|
apiTestCaseMapper.updateByPrimaryKeySelective(apiTestCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ApiCaseCompareData getApiCompareData(String id) {
|
||||||
|
ApiTestCase apiTestCase = checkResourceExist(id);
|
||||||
|
ApiDefinition apiDefinition = getApiDefinition(apiTestCase.getApiDefinitionId());
|
||||||
|
ApiDefinitionBlob apiDefinitionBlob = apiDefinitionBlobMapper.selectByPrimaryKey(apiDefinition.getId());
|
||||||
|
AbstractMsTestElement apiMsTestElement = getApiMsTestElement(apiDefinitionBlob);
|
||||||
|
ApiTestCaseBlob apiTestCaseBlob = apiTestCaseBlobMapper.selectByPrimaryKey(id);
|
||||||
|
AbstractMsTestElement apiTestCaseMsTestElement = getTestElement(apiTestCaseBlob);
|
||||||
|
// 其他协议不处理
|
||||||
|
if (apiMsTestElement instanceof MsHTTPElement apiHttpTestElement && apiTestCaseMsTestElement instanceof MsHTTPElement apiCaseHttpTestElement) {
|
||||||
|
apiMsTestElement = HttpRequestParamDiffUtils.getCompareHttpElement(apiHttpTestElement);
|
||||||
|
apiTestCaseMsTestElement = HttpRequestParamDiffUtils.getCompareHttpElement(apiCaseHttpTestElement);
|
||||||
|
}
|
||||||
|
ApiCaseCompareData apiCaseCompareData = new ApiCaseCompareData();
|
||||||
|
apiCaseCompareData.setApiRequest(apiMsTestElement);
|
||||||
|
apiCaseCompareData.setCaseRequest(apiTestCaseMsTestElement);
|
||||||
|
return apiCaseCompareData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AbstractMsTestElement getApiMsTestElement(ApiDefinitionBlob apiDefinitionBlob) {
|
||||||
|
return ApiDataUtils.parseObject(new String(apiDefinitionBlob.getRequest()), AbstractMsTestElement.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private AbstractMsTestElement getTestElement(ApiTestCaseBlob apiTestCaseBlob) {
|
||||||
|
return ApiDataUtils.parseObject(new String(apiTestCaseBlob.getRequest()), AbstractMsTestElement.class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,13 +4,18 @@ import io.metersphere.api.dto.request.http.MsHTTPElement;
|
||||||
import io.metersphere.api.dto.request.http.body.Body;
|
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.JsonBody;
|
||||||
import io.metersphere.api.dto.request.http.body.XmlBody;
|
import io.metersphere.api.dto.request.http.body.XmlBody;
|
||||||
|
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||||
import io.metersphere.project.api.KeyValueParam;
|
import io.metersphere.project.api.KeyValueParam;
|
||||||
import io.metersphere.sdk.util.EnumValidator;
|
import io.metersphere.sdk.util.EnumValidator;
|
||||||
import io.metersphere.sdk.util.JSON;
|
import io.metersphere.sdk.util.JSON;
|
||||||
|
import io.metersphere.sdk.util.LogUtils;
|
||||||
import io.metersphere.sdk.util.XMLUtils;
|
import io.metersphere.sdk.util.XMLUtils;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.dom4j.Element;
|
||||||
|
import org.dom4j.io.XMLWriter;
|
||||||
|
|
||||||
|
import java.io.StringWriter;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
@ -81,6 +86,7 @@ public class HttpRequestParamDiffUtils {
|
||||||
Object json2 = JSON.parseObject(jsonValue2);
|
Object json2 = JSON.parseObject(jsonValue2);
|
||||||
return !getBlankJon(json1).equals(getBlankJon(json2));
|
return !getBlankJon(json1).equals(getBlankJon(json2));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
LogUtils.info("json 解析异常,json1: {}, json2: {}", jsonValue1, jsonValue2);
|
||||||
return !getJsonKeys(jsonValue1).equals(getJsonKeys(jsonValue2));
|
return !getJsonKeys(jsonValue1).equals(getJsonKeys(jsonValue2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,4 +169,64 @@ public class HttpRequestParamDiffUtils {
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
return !keSet1.equals(keSet2);
|
return !keSet1.equals(keSet2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 json 和 xml 属性值置空
|
||||||
|
* 便于前端比较差异
|
||||||
|
* @param httpElement
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static AbstractMsTestElement getCompareHttpElement(MsHTTPElement httpElement) {
|
||||||
|
Body body = httpElement.getBody();
|
||||||
|
if (body == null) {
|
||||||
|
return httpElement;
|
||||||
|
}
|
||||||
|
if (StringUtils.equals(body.getBodyType(), Body.BodyType.JSON.name())) {
|
||||||
|
try {
|
||||||
|
String jsonValue = body.getJsonBody().getJsonValue();
|
||||||
|
jsonValue = replaceIllegalJsonWithMock(jsonValue);
|
||||||
|
Object blankJon = getBlankJon(JSON.parseObject(jsonValue));
|
||||||
|
body.getJsonBody().setJsonValue(JSON.toJSONString(blankJon));
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtils.info("json 解析异常,json: {}", body.getJsonBody().getJsonValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (StringUtils.equals(body.getBodyType(), Body.BodyType.XML.name())) {
|
||||||
|
String xml = body.getXmlBody().getValue();
|
||||||
|
try {
|
||||||
|
Element element = XMLUtils.stringToDocument(xml).getRootElement();
|
||||||
|
XMLUtils.clearElementText(element);
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
XMLWriter writer = new XMLWriter(stringWriter);
|
||||||
|
writer.write(element);
|
||||||
|
xml = stringWriter.toString();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtils.info("xml 解析异常,xml: {}", body.getXmlBody().getValue());
|
||||||
|
xml = XMLUtils.clearElementText(xml);
|
||||||
|
}
|
||||||
|
body.getXmlBody().setValue(xml);
|
||||||
|
}
|
||||||
|
return httpElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 如果 json 串中包含了非字符串的 mock 函数
|
||||||
|
* 例如:
|
||||||
|
* {"a": @integer(1, 2)}
|
||||||
|
* 替换成空字符串
|
||||||
|
* {"a": ""}
|
||||||
|
* 避免 json 序列化失败
|
||||||
|
* @param text
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static String replaceIllegalJsonWithMock(String text) {
|
||||||
|
String pattern = ":\\s*(@\\w+(\\(\\s*\\w*\\s*,?\\s*\\w*\\s*\\))*)";
|
||||||
|
Pattern regex = Pattern.compile(pattern);
|
||||||
|
Matcher matcher = regex.matcher(text);
|
||||||
|
while (matcher.find()) {
|
||||||
|
// 这里连同:一起替换,避免替换了其他合规的参数值
|
||||||
|
text = text.replaceFirst(pattern, ":\"\"");
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,7 +110,8 @@ public class ApiTestCaseControllerTests extends BaseTest {
|
||||||
private static final String RUN_GET = "run/{0}";
|
private static final String RUN_GET = "run/{0}";
|
||||||
private static final String RUN_POST = "run";
|
private static final String RUN_POST = "run";
|
||||||
private static final String BATCH_RUN = "batch/run";
|
private static final String BATCH_RUN = "batch/run";
|
||||||
private static final String API_CHANGE_CLEAR = "api-change/clear/{id}";
|
private static final String API_CHANGE_CLEAR = "api-change/clear/{0}";
|
||||||
|
private static final String API_COMPARE = "api/compare/{0}";
|
||||||
|
|
||||||
private static final ResultMatcher ERROR_REQUEST_MATCHER = status().is5xxServerError();
|
private static final ResultMatcher ERROR_REQUEST_MATCHER = status().is5xxServerError();
|
||||||
private static ApiTestCase apiTestCase;
|
private static ApiTestCase apiTestCase;
|
||||||
|
@ -438,6 +439,18 @@ public class ApiTestCaseControllerTests extends BaseTest {
|
||||||
Assertions.assertEquals(apiTestCaseMapper.selectByPrimaryKey(apiTestCase.getId()).getApiChange(), true);
|
Assertions.assertEquals(apiTestCaseMapper.selectByPrimaryKey(apiTestCase.getId()).getApiChange(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(3)
|
||||||
|
public void getApiCompareData() throws Exception {
|
||||||
|
// @@请求成功
|
||||||
|
MvcResult mvcResult = this.requestGetWithOkAndReturn(API_COMPARE, apiTestCase.getId());
|
||||||
|
Map apiCaseCompareData = (Map) parseResponse(mvcResult).get("data");
|
||||||
|
Assertions.assertNotNull(apiCaseCompareData.get("apiRequest"));
|
||||||
|
Assertions.assertNotNull(apiCaseCompareData.get("caseRequest"));
|
||||||
|
// @@校验权限
|
||||||
|
requestGetPermissionTest(PermissionConstants.PROJECT_API_DEFINITION_CASE_READ, API_COMPARE, apiTestCase.getId());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Order(3)
|
@Order(3)
|
||||||
public void clearApiChange() throws Exception {
|
public void clearApiChange() throws Exception {
|
||||||
|
|
|
@ -7,9 +7,13 @@ import io.metersphere.api.dto.request.http.RestParam;
|
||||||
import io.metersphere.api.dto.request.http.body.*;
|
import io.metersphere.api.dto.request.http.body.*;
|
||||||
import io.metersphere.project.api.KeyValueParam;
|
import io.metersphere.project.api.KeyValueParam;
|
||||||
import io.metersphere.sdk.util.JSON;
|
import io.metersphere.sdk.util.JSON;
|
||||||
|
import io.metersphere.sdk.util.XMLUtils;
|
||||||
|
import org.dom4j.Element;
|
||||||
|
import org.dom4j.io.XMLWriter;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.StringWriter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -332,4 +336,148 @@ public class HttpRequestParamDiffUtilsTests {
|
||||||
msHTTPElement1.setBody(new Body());
|
msHTTPElement1.setBody(new Body());
|
||||||
Assertions.assertTrue(HttpRequestParamDiffUtils.isRequestParamDiff(msHTTPElement1, msHTTPElement2));
|
Assertions.assertTrue(HttpRequestParamDiffUtils.isRequestParamDiff(msHTTPElement1, msHTTPElement2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void replaceIllegalJsonWithMock() {
|
||||||
|
String replaceJon = HttpRequestParamDiffUtils.replaceIllegalJsonWithMock("""
|
||||||
|
{
|
||||||
|
"id": "dddd",
|
||||||
|
"age": 10,
|
||||||
|
"name": @integer(1, 10),
|
||||||
|
"category": {
|
||||||
|
"id":@integer(1),
|
||||||
|
"name": @integer,
|
||||||
|
"title": @integer(1, 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""");
|
||||||
|
|
||||||
|
Object result = JSON.parseObject("""
|
||||||
|
{
|
||||||
|
"id": "dddd",
|
||||||
|
"age": 10,
|
||||||
|
"name": "",
|
||||||
|
"category": {
|
||||||
|
"id": "",
|
||||||
|
"name": "",
|
||||||
|
"title": ""
|
||||||
|
}
|
||||||
|
}""");
|
||||||
|
|
||||||
|
Assertions.assertEquals(JSON.parseObject(replaceJon), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void clearElementText() throws Exception {
|
||||||
|
String xml = """
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>3.2.8</version>
|
||||||
|
<relativePath/>
|
||||||
|
</parent>
|
||||||
|
</project>
|
||||||
|
""";
|
||||||
|
|
||||||
|
Element element = XMLUtils.stringToDocument(xml).getRootElement();
|
||||||
|
XMLUtils.clearElementText(element);
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
XMLWriter writer = new XMLWriter(stringWriter);
|
||||||
|
writer.write(element);
|
||||||
|
stringWriter.toString();
|
||||||
|
|
||||||
|
String result = """
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion></modelVersion><parent><groupId></groupId><artifactId></artifactId><version></version><relativePath></relativePath></parent></project>""";
|
||||||
|
|
||||||
|
Assertions.assertEquals(stringWriter.toString(), result);
|
||||||
|
|
||||||
|
|
||||||
|
String regexResult = """
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion></modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId></groupId>
|
||||||
|
<artifactId></artifactId>
|
||||||
|
<version></version>
|
||||||
|
<relativePath/></parent>
|
||||||
|
</project>
|
||||||
|
""";
|
||||||
|
Assertions.assertEquals(XMLUtils.clearElementText(xml), regexResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getCompareHttpElement() {
|
||||||
|
MsHTTPElement msHTTPElement = new MsHTTPElement();
|
||||||
|
HttpRequestParamDiffUtils.getCompareHttpElement(msHTTPElement);
|
||||||
|
|
||||||
|
msHTTPElement.setBody(new Body());
|
||||||
|
Body body = msHTTPElement.getBody();
|
||||||
|
body.setJsonBody(new JsonBody());
|
||||||
|
body.setBodyType(Body.BodyType.RAW.name());
|
||||||
|
HttpRequestParamDiffUtils.getCompareHttpElement(msHTTPElement);
|
||||||
|
|
||||||
|
body.setBodyType(Body.BodyType.JSON.name());
|
||||||
|
String jsonValue = """
|
||||||
|
{
|
||||||
|
"id": "dddd",
|
||||||
|
"age": 10,
|
||||||
|
"name": @integer(1, 10),
|
||||||
|
"category": {
|
||||||
|
"id":@integer(1),
|
||||||
|
"name": @integer,
|
||||||
|
"title": @integer(1, 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
body.getJsonBody().setJsonValue(jsonValue);
|
||||||
|
HttpRequestParamDiffUtils.getCompareHttpElement(msHTTPElement);
|
||||||
|
Assertions.assertEquals(JSON.parseObject(body.getJsonBody().getJsonValue()), JSON.parseObject("""
|
||||||
|
{
|
||||||
|
"id": "",
|
||||||
|
"age": "",
|
||||||
|
"name": "",
|
||||||
|
"category": {
|
||||||
|
"id": "",
|
||||||
|
"name": "",
|
||||||
|
"title": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""));
|
||||||
|
|
||||||
|
String xmlValue = """
|
||||||
|
<project>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org</groupId>
|
||||||
|
<artifactId>spring</artifactId>
|
||||||
|
<version>3.2.8</version>
|
||||||
|
<relativePath/>
|
||||||
|
</parent>
|
||||||
|
</project>
|
||||||
|
""";
|
||||||
|
msHTTPElement.getBody().setBodyType(Body.BodyType.XML.name());
|
||||||
|
body.setXmlBody(new XmlBody());
|
||||||
|
body.getXmlBody().setValue(xmlValue);
|
||||||
|
HttpRequestParamDiffUtils.getCompareHttpElement(msHTTPElement);
|
||||||
|
|
||||||
|
|
||||||
|
xmlValue = """
|
||||||
|
dx
|
||||||
|
<project>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org</groupId>
|
||||||
|
<artifactId>spring</artifactId>
|
||||||
|
<version>3.2.8</version>
|
||||||
|
<relativePath/>
|
||||||
|
</parent>
|
||||||
|
</project>
|
||||||
|
""";
|
||||||
|
body.getXmlBody().setValue(xmlValue);
|
||||||
|
HttpRequestParamDiffUtils.getCompareHttpElement(msHTTPElement);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue