feat(接口测试): 用例同步相关接口
--task=1015860 --user=陈建星 【接口测试】接口用例支持同步更新接口变更-后端-批量同步更新接口 https://www.tapd.cn/55049933/s/1559954
This commit is contained in:
parent
37ae81423c
commit
a9da9a7a59
|
@ -11,6 +11,7 @@ import io.metersphere.api.dto.definition.*;
|
|||
import io.metersphere.api.dto.request.ApiTransferRequest;
|
||||
import io.metersphere.api.service.ApiFileResourceService;
|
||||
import io.metersphere.api.service.definition.*;
|
||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||
import io.metersphere.project.service.FileModuleService;
|
||||
import io.metersphere.sdk.constants.DefaultRepositoryDir;
|
||||
import io.metersphere.sdk.constants.PermissionConstants;
|
||||
|
@ -326,6 +327,14 @@ public class ApiTestCaseController {
|
|||
apiTestCaseService.ignoreApiChange(id, ignore);
|
||||
}
|
||||
|
||||
@PostMapping("/api-change/sync")
|
||||
@Operation(summary = "获取同步后的用例详情")
|
||||
@RequiresPermissions(value = PermissionConstants.PROJECT_API_DEFINITION_CASE_UPDATE)
|
||||
@CheckOwner(resourceId = "#request.getId()", resourceType = "api_test_case")
|
||||
public AbstractMsTestElement syncApiChange(@Validated @RequestBody ApiCaseSyncRequest request) {
|
||||
return apiTestCaseService.syncApiChange(request);
|
||||
}
|
||||
|
||||
@GetMapping("/api/compare/{id}")
|
||||
@Operation(summary = "与接口定义对比")
|
||||
@RequiresPermissions(value = PermissionConstants.PROJECT_API_DEFINITION_CASE_READ)
|
||||
|
|
|
@ -2,12 +2,10 @@ package io.metersphere.api.dto.definition;
|
|||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class ApiCaseBatchSyncRequest extends ApiTestCaseBatchRequest implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
@ -15,22 +13,12 @@ public class ApiCaseBatchSyncRequest extends ApiTestCaseBatchRequest implements
|
|||
@Schema(description = "同步项")
|
||||
private ApiCaseSyncItemRequest syncItems = new ApiCaseSyncItemRequest();
|
||||
@Schema(description = "是否删除多余参数", defaultValue = "false")
|
||||
private boolean deleteRedundantParam = false;
|
||||
private Boolean deleteRedundantParam = false;
|
||||
@Schema(description = "通知配置")
|
||||
private ApiCaseSyncNotificationRequest notificationConfig = new ApiCaseSyncNotificationRequest();
|
||||
|
||||
public class ApiCaseSyncItemRequest {
|
||||
@Schema(description = "请求头", defaultValue = "true")
|
||||
private Boolean header = true;
|
||||
@Schema(description = "请求体", defaultValue = "true")
|
||||
private Boolean body = true;
|
||||
@Schema(description = "Query参数", defaultValue = "true")
|
||||
private Boolean query = true;
|
||||
@Schema(description = "Rest参数", defaultValue = "true")
|
||||
private Boolean rest = true;
|
||||
}
|
||||
|
||||
public class ApiCaseSyncNotificationRequest {
|
||||
@Data
|
||||
public static class ApiCaseSyncNotificationRequest {
|
||||
@Schema(description = "是否通知接口创建人", defaultValue = "true")
|
||||
private Boolean apiCreator = true;
|
||||
@Schema(description = "是否通知引用该用例的场景创建人", defaultValue = "true")
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package io.metersphere.api.dto.definition;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2024-08-08 11:06
|
||||
*/
|
||||
@Data
|
||||
public class ApiCaseSyncItemRequest implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "请求头", defaultValue = "true")
|
||||
private Boolean header = true;
|
||||
@Schema(description = "请求体", defaultValue = "true")
|
||||
private Boolean body = true;
|
||||
@Schema(description = "Query参数", defaultValue = "true")
|
||||
private Boolean query = true;
|
||||
@Schema(description = "Rest参数", defaultValue = "true")
|
||||
private Boolean rest = true;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package io.metersphere.api.dto.definition;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class ApiCaseSyncRequest implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "同步项")
|
||||
private ApiCaseSyncItemRequest syncItems = new ApiCaseSyncItemRequest();
|
||||
@Schema(description = "是否删除多余参数", defaultValue = "false")
|
||||
private Boolean deleteRedundantParam = false;
|
||||
@Schema(description = "用例的请求详情")
|
||||
@NotNull
|
||||
private Object apiCaseRequest;
|
||||
@Schema(description = "用例ID")
|
||||
@NotBlank
|
||||
private String id;
|
||||
}
|
|
@ -111,4 +111,6 @@ public interface ExtApiTestCaseMapper {
|
|||
List<ApiTestCase> getCaseListBySelectIds(@Param("isRepeat") boolean isRepeat, @Param("projectId") String projectId, @Param("ids") List<String> ids, @Param("testPlanId") String testPlanId, @Param("protocols") List<String> protocols);
|
||||
|
||||
void setApiChangeByApiDefinitionId(@Param("apiDefinitionId") String apiDefinitionId);
|
||||
|
||||
List<ApiTestCase> getApiCaseForBatchSync(@Param("ids") List<String> ids);
|
||||
}
|
|
@ -727,6 +727,14 @@
|
|||
)
|
||||
</if>
|
||||
</select>
|
||||
<select id="getApiCaseForBatchSync" resultType="io.metersphere.api.domain.ApiTestCase">
|
||||
select id, api_definition_id
|
||||
from api_test_case
|
||||
where id in
|
||||
<foreach collection="ids" item="id" separator="," open="(" close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</select>
|
||||
|
||||
|
||||
</mapper>
|
|
@ -1,5 +1,6 @@
|
|||
package io.metersphere.api.service.definition;
|
||||
|
||||
import io.metersphere.api.constants.ApiConstants;
|
||||
import io.metersphere.api.constants.ApiResourceType;
|
||||
import io.metersphere.api.domain.*;
|
||||
import io.metersphere.api.dto.*;
|
||||
|
@ -462,7 +463,6 @@ public class ApiTestCaseService extends MoveNodeService {
|
|||
}
|
||||
|
||||
public void batchEdit(ApiCaseBatchEditRequest request, String userId) {
|
||||
|
||||
List<String> ids = doSelectIds(request, false);
|
||||
if (CollectionUtils.isEmpty(ids)) {
|
||||
return;
|
||||
|
@ -995,6 +995,56 @@ public class ApiTestCaseService extends MoveNodeService {
|
|||
}
|
||||
|
||||
public void batchSyncApiChange(ApiCaseBatchSyncRequest request, String userId) {
|
||||
// todo
|
||||
// 只处理 http 协议的接口
|
||||
request.setProtocols(List.of(ApiConstants.HTTP_PROTOCOL));
|
||||
List<String> ids = doSelectIds(request, false);
|
||||
if (CollectionUtils.isEmpty(ids)) {
|
||||
return;
|
||||
}
|
||||
SubListUtils.dealForSubList(ids, 500, subList -> doBatchSyncApiChange(request, subList, userId));
|
||||
}
|
||||
|
||||
public void doBatchSyncApiChange(ApiCaseBatchSyncRequest request, List<String> ids, String userId) {
|
||||
List<ApiTestCase> apiTestCases = extApiTestCaseMapper.getApiCaseForBatchSync(ids);
|
||||
Set<String> apiDefinitionIds = apiTestCases.stream().map(ApiTestCase::getApiDefinitionId).collect(Collectors.toSet());
|
||||
Map<String, ApiTestCase> apiTestCaseMap = apiTestCases.stream().collect(Collectors.toMap(ApiTestCase::getApiDefinitionId, Function.identity()));
|
||||
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
||||
ApiTestCaseBlobMapper apiTestCaseBlobBatchMapper = sqlSession.getMapper(ApiTestCaseBlobMapper.class);
|
||||
ApiTestCaseMapper apiTestCaseBatchMapper = sqlSession.getMapper(ApiTestCaseMapper.class);
|
||||
|
||||
ApiCaseSyncRequest apiCaseSyncRequest = new ApiCaseSyncRequest();
|
||||
apiCaseSyncRequest.setSyncItems(request.getSyncItems());
|
||||
apiCaseSyncRequest.setDeleteRedundantParam(request.getDeleteRedundantParam());
|
||||
try {
|
||||
for (String apiDefinitionId : apiDefinitionIds) {
|
||||
ApiDefinitionBlob apiDefinitionBlob = apiDefinitionBlobMapper.selectByPrimaryKey(apiDefinitionId);
|
||||
AbstractMsTestElement apiMsTestElement = getApiMsTestElement(apiDefinitionBlob);
|
||||
ApiTestCase apiTestCase = apiTestCaseMap.get(apiDefinitionId);
|
||||
ApiTestCaseBlob apiTestCaseBlob = apiTestCaseBlobMapper.selectByPrimaryKey(apiTestCase.getId());
|
||||
AbstractMsTestElement apiTestCaseMsTestElement = getTestElement(apiTestCaseBlob);
|
||||
boolean requestParamDifferent = HttpRequestParamDiffUtils.isRequestParamDiff(request.getSyncItems(), apiMsTestElement, apiTestCaseMsTestElement);
|
||||
if (requestParamDifferent) {
|
||||
apiTestCase.setUpdateTime(System.currentTimeMillis());
|
||||
apiTestCase.setUpdateUser(userId);
|
||||
apiTestCase.setApiChange(false);
|
||||
apiTestCaseBatchMapper.updateByPrimaryKeySelective(apiTestCase);
|
||||
apiTestCaseMsTestElement = HttpRequestParamDiffUtils.syncRequestDiff(apiCaseSyncRequest, apiMsTestElement, apiTestCaseMsTestElement);
|
||||
apiTestCaseBlob.setRequest(ApiDataUtils.toJSONString(apiTestCaseMsTestElement).getBytes());
|
||||
apiTestCaseBlobBatchMapper.updateByPrimaryKeySelective(apiTestCaseBlob);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
sqlSession.flushStatements();
|
||||
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
|
||||
}
|
||||
}
|
||||
|
||||
public AbstractMsTestElement syncApiChange(ApiCaseSyncRequest request) {
|
||||
ApiTestCase apiTestCase = checkResourceExist(request.getId());
|
||||
ApiDefinition apiDefinition = getApiDefinition(apiTestCase.getApiDefinitionId());
|
||||
ApiDefinitionBlob apiDefinitionBlob = apiDefinitionBlobMapper.selectByPrimaryKey(apiDefinition.getId());
|
||||
AbstractMsTestElement apiMsTestElement = getApiMsTestElement(apiDefinitionBlob);
|
||||
AbstractMsTestElement apiTestCaseMsTestElement = ApiDataUtils.parseObject(JSON.toJSONString(request.getApiCaseRequest()), AbstractMsTestElement.class);
|
||||
return HttpRequestParamDiffUtils.syncRequestDiff(request, apiMsTestElement, apiTestCaseMsTestElement);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package io.metersphere.api.utils;
|
||||
|
||||
import io.metersphere.api.dto.definition.ApiCaseSyncItemRequest;
|
||||
import io.metersphere.api.dto.definition.ApiCaseSyncRequest;
|
||||
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.JsonBody;
|
||||
import io.metersphere.api.dto.request.http.body.XmlBody;
|
||||
import io.metersphere.api.dto.request.http.body.*;
|
||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||
import io.metersphere.project.api.KeyValueParam;
|
||||
import io.metersphere.sdk.util.EnumValidator;
|
||||
|
@ -11,16 +11,21 @@ import io.metersphere.sdk.util.JSON;
|
|||
import io.metersphere.sdk.util.LogUtils;
|
||||
import io.metersphere.sdk.util.XMLUtils;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dom4j.Element;
|
||||
import org.dom4j.io.XMLWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static io.metersphere.sdk.util.XMLUtils.elementToMap;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2024-08-01 14:01
|
||||
|
@ -28,6 +33,10 @@ import java.util.stream.Collectors;
|
|||
public class HttpRequestParamDiffUtils {
|
||||
|
||||
public static boolean isRequestParamDiff(Object request1, Object request2) {
|
||||
return isRequestParamDiff(new ApiCaseSyncItemRequest(), request1, request2);
|
||||
}
|
||||
|
||||
public static boolean isRequestParamDiff(ApiCaseSyncItemRequest syncItemRequest, Object request1, Object request2) {
|
||||
if (!(request1 instanceof MsHTTPElement)) {
|
||||
// 其他协议不比较
|
||||
return false;
|
||||
|
@ -38,6 +47,13 @@ public class HttpRequestParamDiffUtils {
|
|||
boolean isRestDiff = isParamKeyDiff(httpElement1.getRest(), httpElement2.getRest());
|
||||
boolean isHeaderDiff = isParamKeyDiff(httpElement1.getHeaders(), httpElement2.getHeaders());
|
||||
boolean isBodyDiff = isBodyDiff(httpElement1.getBody(), httpElement2.getBody());
|
||||
|
||||
// 设置需要同步的同步项, 减少比较次数
|
||||
syncItemRequest.setBody(isBodyDiff && BooleanUtils.isTrue(syncItemRequest.getBody()));
|
||||
syncItemRequest.setHeader(isHeaderDiff && BooleanUtils.isTrue(syncItemRequest.getHeader()));
|
||||
syncItemRequest.setQuery(isQueryDiff && BooleanUtils.isTrue(syncItemRequest.getQuery()));
|
||||
syncItemRequest.setRest(isRestDiff && BooleanUtils.isTrue(syncItemRequest.getRest()));
|
||||
|
||||
if (isQueryDiff || isRestDiff || isHeaderDiff || isBodyDiff) {
|
||||
return true;
|
||||
}
|
||||
|
@ -94,6 +110,7 @@ public class HttpRequestParamDiffUtils {
|
|||
/**
|
||||
* 将json对象的属性值都置空
|
||||
* 便于比较参数名是否一致
|
||||
*
|
||||
* @param obj
|
||||
* @return
|
||||
*/
|
||||
|
@ -124,6 +141,7 @@ public class HttpRequestParamDiffUtils {
|
|||
* 因为数值类型使用 mock 函数,会导致 json 串为非法 json 串
|
||||
* 这里使用正则表达式获取key
|
||||
* 使用 LinkedHashSet 按序获取,近似比较两个 json 串的 key
|
||||
*
|
||||
* @param jsonValue
|
||||
* @return
|
||||
*/
|
||||
|
@ -148,8 +166,8 @@ public class HttpRequestParamDiffUtils {
|
|||
return true;
|
||||
}
|
||||
try {
|
||||
Set<String> keySet1 = XMLUtils.elementToMap(XMLUtils.stringToDocument(value1).getRootElement()).keySet();
|
||||
Set<String> keySet2 = XMLUtils.elementToMap(XMLUtils.stringToDocument(value2).getRootElement()).keySet();
|
||||
Set<String> keySet1 = elementToMap(XMLUtils.stringToDocument(value1).getRootElement()).keySet();
|
||||
Set<String> keySet2 = elementToMap(XMLUtils.stringToDocument(value2).getRootElement()).keySet();
|
||||
return !keySet1.equals(keySet2);
|
||||
} catch (Exception e) {
|
||||
return !StringUtils.equals(value1, value2);
|
||||
|
@ -173,6 +191,7 @@ public class HttpRequestParamDiffUtils {
|
|||
/**
|
||||
* 将 json 和 xml 属性值置空
|
||||
* 便于前端比较差异
|
||||
*
|
||||
* @param httpElement
|
||||
* @return
|
||||
*/
|
||||
|
@ -192,7 +211,7 @@ public class HttpRequestParamDiffUtils {
|
|||
}
|
||||
}
|
||||
if (StringUtils.equals(body.getBodyType(), Body.BodyType.XML.name())) {
|
||||
String xml = body.getXmlBody().getValue();
|
||||
String xml = Optional.ofNullable(body.getXmlBody().getValue()).orElse(StringUtils.EMPTY);
|
||||
try {
|
||||
Element element = XMLUtils.stringToDocument(xml).getRootElement();
|
||||
XMLUtils.clearElementText(element);
|
||||
|
@ -216,6 +235,7 @@ public class HttpRequestParamDiffUtils {
|
|||
* 替换成空字符串
|
||||
* {"a": ""}
|
||||
* 避免 json 序列化失败
|
||||
*
|
||||
* @param text
|
||||
* @return
|
||||
*/
|
||||
|
@ -229,4 +249,320 @@ public class HttpRequestParamDiffUtils {
|
|||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步请求参数
|
||||
* @param request
|
||||
* @param sourceElement
|
||||
* @param targetElement
|
||||
* @return
|
||||
*/
|
||||
public static AbstractMsTestElement syncRequestDiff(ApiCaseSyncRequest request,
|
||||
AbstractMsTestElement sourceElement, AbstractMsTestElement targetElement) {
|
||||
if (!(sourceElement instanceof MsHTTPElement)) {
|
||||
// 其他协议不比较
|
||||
return targetElement;
|
||||
}
|
||||
MsHTTPElement sourceHttpElement = (MsHTTPElement) sourceElement;
|
||||
MsHTTPElement targetHttpElement = (MsHTTPElement) targetElement;
|
||||
boolean isDeleteRedundantParam = BooleanUtils.isTrue(request.getDeleteRedundantParam());
|
||||
ApiCaseSyncItemRequest syncItems = request.getSyncItems();
|
||||
if (BooleanUtils.isTrue(syncItems.getHeader())) {
|
||||
targetHttpElement.setHeaders(
|
||||
syncKeyValueParamDiff(isDeleteRedundantParam, sourceHttpElement.getHeaders(), targetHttpElement.getHeaders())
|
||||
);
|
||||
}
|
||||
|
||||
if (BooleanUtils.isTrue(syncItems.getRest())) {
|
||||
targetHttpElement.setRest(
|
||||
syncKeyValueParamDiff(isDeleteRedundantParam, sourceHttpElement.getRest(), targetHttpElement.getRest())
|
||||
);
|
||||
}
|
||||
|
||||
if (BooleanUtils.isTrue(syncItems.getQuery())) {
|
||||
targetHttpElement.setQuery(
|
||||
syncKeyValueParamDiff(isDeleteRedundantParam, sourceHttpElement.getQuery(), targetHttpElement.getQuery())
|
||||
);
|
||||
}
|
||||
|
||||
if (BooleanUtils.isTrue(syncItems.getBody())) {
|
||||
Body sourceBody = sourceHttpElement.getBody();
|
||||
Body targetBody = targetHttpElement.getBody();
|
||||
targetBody = syncBodyDiff(isDeleteRedundantParam, sourceBody, targetBody);
|
||||
targetHttpElement.setBody(targetBody);
|
||||
}
|
||||
|
||||
return targetElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步 body 参数
|
||||
* @param isDeleteRedundantParam
|
||||
* @param sourceBody
|
||||
* @param targetBody
|
||||
* @return
|
||||
*/
|
||||
public static Body syncBodyDiff(boolean isDeleteRedundantParam, Body sourceBody, Body targetBody) {
|
||||
if (sourceBody == null || targetBody == null || sourceBody.getBodyType() != targetBody.getBodyType()) {
|
||||
return sourceBody;
|
||||
}
|
||||
Body.BodyType bodyType = EnumValidator.validateEnum(Body.BodyType.class, sourceBody.getBodyType());
|
||||
switch (bodyType) {
|
||||
case FORM_DATA -> {
|
||||
List<FormDataKV> formDataKVS = syncKeyValueParamDiff(isDeleteRedundantParam, sourceBody.getFormDataBody().getFormValues(), targetBody.getFormDataBody().getFormValues());
|
||||
targetBody.getFormDataBody().setFormValues(formDataKVS);
|
||||
}
|
||||
case WWW_FORM -> {
|
||||
List<WWWFormKV> wwwFormKVS = syncKeyValueParamDiff(isDeleteRedundantParam, sourceBody.getWwwFormBody().getFormValues(), targetBody.getWwwFormBody().getFormValues());
|
||||
targetBody.getWwwFormBody().setFormValues(wwwFormKVS);
|
||||
}
|
||||
case JSON -> {
|
||||
JsonBody jsonBody = syncJsonBodyDiff(isDeleteRedundantParam, sourceBody.getJsonBody(), targetBody.getJsonBody());
|
||||
targetBody.setJsonBody(jsonBody);
|
||||
}
|
||||
case XML -> {
|
||||
XmlBody xmlBody = syncXmlBodyDiff(isDeleteRedundantParam, sourceBody.getXmlBody(), targetBody.getXmlBody());
|
||||
targetBody.setXmlBody(xmlBody);
|
||||
}
|
||||
default -> {}
|
||||
// RAW,BINARY 不同步
|
||||
}
|
||||
return targetBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步 json 参数
|
||||
* @param isDeleteRedundantParam
|
||||
* @param sourceBody
|
||||
* @param targetBody
|
||||
* @return
|
||||
*/
|
||||
public static JsonBody syncJsonBodyDiff(boolean isDeleteRedundantParam, JsonBody sourceBody, JsonBody targetBody) {
|
||||
if (sourceBody == null) {
|
||||
return isDeleteRedundantParam ? new JsonBody() : targetBody;
|
||||
}
|
||||
if (targetBody == null) {
|
||||
return sourceBody;
|
||||
}
|
||||
|
||||
String sourceJsonStr = sourceBody.getJsonValue();
|
||||
String targetJsonStr = targetBody.getJsonValue();
|
||||
if (StringUtils.isBlank(sourceJsonStr)) {
|
||||
return isDeleteRedundantParam ? new JsonBody() : targetBody;
|
||||
}
|
||||
if (StringUtils.isBlank(targetJsonStr)) {
|
||||
return sourceBody;
|
||||
}
|
||||
|
||||
try {
|
||||
Object sourceJson = JSON.parseObject(sourceJsonStr);
|
||||
Object targetJson = JSON.parseObject(targetJsonStr);
|
||||
targetJson = syncJsonBodyDiff(isDeleteRedundantParam, sourceJson, targetJson);
|
||||
targetBody.setJsonValue(JSON.toJSONString(targetJson));
|
||||
} catch (Exception e) {
|
||||
LogUtils.info("同步参数 json 解析异常,json1: {}, json2: {}", sourceJsonStr, targetJsonStr);
|
||||
// todo 处理非法 json
|
||||
}
|
||||
return targetBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步 xml 参数
|
||||
* @param isDeleteRedundantParam
|
||||
* @param sourceBody
|
||||
* @param targetBody
|
||||
* @return
|
||||
*/
|
||||
public static XmlBody syncXmlBodyDiff(boolean isDeleteRedundantParam, XmlBody sourceBody, XmlBody targetBody) {
|
||||
if (sourceBody == null) {
|
||||
return isDeleteRedundantParam ? new XmlBody() : targetBody;
|
||||
}
|
||||
if (targetBody == null) {
|
||||
return sourceBody;
|
||||
}
|
||||
|
||||
String sourceXmlStr = sourceBody.getValue();
|
||||
String targetXmlStr = targetBody.getValue();
|
||||
if (StringUtils.isBlank(sourceXmlStr)) {
|
||||
return isDeleteRedundantParam ? new XmlBody() : targetBody;
|
||||
}
|
||||
if (StringUtils.isBlank(targetXmlStr)) {
|
||||
return sourceBody;
|
||||
}
|
||||
|
||||
try {
|
||||
Element sourceElement = XMLUtils.stringToDocument(sourceXmlStr).getRootElement();
|
||||
Element targetElement = XMLUtils.stringToDocument(targetXmlStr).getRootElement();
|
||||
targetElement = syncXmlBodyDiff(isDeleteRedundantParam, sourceElement, targetElement);
|
||||
String string = parseElementToString(targetElement);
|
||||
targetBody.setValue(string);
|
||||
} catch (Exception e) {
|
||||
LogUtils.info("同步参数 xml 解析异常,xml1: {}, xml2: {}", sourceXmlStr, targetXmlStr);
|
||||
}
|
||||
return targetBody;
|
||||
}
|
||||
|
||||
public static String parseElementToString(Element element) throws IOException {
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
XMLWriter writer = new XMLWriter(stringWriter);
|
||||
writer.write(element);
|
||||
return stringWriter.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步 xml 参数
|
||||
* @param isDeleteRedundantParam
|
||||
* @param source
|
||||
* @param target
|
||||
* @return
|
||||
*/
|
||||
public static Element syncXmlBodyDiff(boolean isDeleteRedundantParam, Element source, Element target) {
|
||||
if (source == null) {
|
||||
return isDeleteRedundantParam ? null : target.createCopy();
|
||||
}
|
||||
if (target == null) {
|
||||
return source.createCopy();
|
||||
}
|
||||
|
||||
List<Element> sourceElements = source.elements();
|
||||
List<Element> targetElements = target.elements();
|
||||
|
||||
Map<String, Element> sourceElementMap = sourceElements.stream().collect(Collectors.toMap(Element::getName, Function.identity()));
|
||||
Map<String, Element> targetElementMap = targetElements.stream().collect(Collectors.toMap(Element::getName, Function.identity()));
|
||||
|
||||
// 删除多余参数
|
||||
if (isDeleteRedundantParam) {
|
||||
Iterator<Element> iterator = targetElements.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Element element = iterator.next();
|
||||
if (!sourceElementMap.keySet().contains(element.getName())) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < sourceElements.size(); i++) {
|
||||
Element sourceElement = sourceElements.get(i);
|
||||
Element targetElement = targetElementMap.get(sourceElement.getName());
|
||||
if (targetElement == null) {
|
||||
// 添加新增参数
|
||||
target.add(sourceElement.createCopy());
|
||||
} else {
|
||||
int index = targetElements.indexOf(targetElement);
|
||||
targetElement = syncXmlBodyDiff(isDeleteRedundantParam, sourceElement, targetElement);
|
||||
targetElements.set(index, targetElement);
|
||||
}
|
||||
}
|
||||
return target.createCopy();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 同步 json 参数
|
||||
* @param sourceJson
|
||||
* @param targetJson
|
||||
* @return
|
||||
*/
|
||||
public static Object syncJsonBodyDiff(boolean isDeleteRedundantParam, Object sourceJson, Object targetJson) {
|
||||
if (sourceJson == null) {
|
||||
return isDeleteRedundantParam ? null : targetJson;
|
||||
}
|
||||
if (targetJson == null) {
|
||||
return sourceJson;
|
||||
}
|
||||
if (sourceJson.getClass() != targetJson.getClass()) {
|
||||
return sourceJson;
|
||||
}
|
||||
if (sourceJson instanceof Map sourceMap && targetJson instanceof Map targetMap) {
|
||||
// 删除多余参数
|
||||
if (isDeleteRedundantParam) {
|
||||
Iterator iterator = targetMap.keySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
String key = (String) iterator.next();
|
||||
if (!sourceMap.keySet().contains(key)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceMap.forEach((key, sourceValue) -> {
|
||||
if (!targetMap.keySet().contains(key)) {
|
||||
targetMap.put(key, sourceValue);
|
||||
// 添加新增参数
|
||||
} else {
|
||||
Object targetValue = targetMap.get(key);
|
||||
targetMap.put(key, syncJsonBodyDiff(isDeleteRedundantParam, sourceValue, targetValue));
|
||||
}
|
||||
});
|
||||
} else if (sourceJson instanceof List souceList && targetJson instanceof List targetList) {
|
||||
int size = Math.min(souceList.size(), targetList.size());
|
||||
for (int i = 0; i < size; i++) {
|
||||
Object sourceValue = souceList.get(i);
|
||||
Object targetValue = targetList.get(i);
|
||||
targetList.set(i, syncJsonBodyDiff(isDeleteRedundantParam, sourceValue, targetValue));
|
||||
}
|
||||
}
|
||||
return targetJson;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 同步键值对参数
|
||||
* @param deleteRedundantParam
|
||||
* @param sourceParams
|
||||
* @param targetParams
|
||||
* @return
|
||||
* @param <T>
|
||||
*/
|
||||
public static <T extends KeyValueParam> List<T> syncKeyValueParamDiff(
|
||||
boolean deleteRedundantParam, List<T> sourceParams, List<T> targetParams) {
|
||||
if (sourceParams == null) {
|
||||
return deleteRedundantParam ? new ArrayList<>(0) : targetParams;
|
||||
}
|
||||
if (targetParams == null) {
|
||||
return sourceParams;
|
||||
}
|
||||
Map<String, ? extends KeyValueParam> sourceMaps = sourceParams.stream()
|
||||
.filter(KeyValueParam::isValid)
|
||||
.collect(Collectors.toMap(KeyValueParam::getKey, Function.identity()));
|
||||
|
||||
// 删除多余参数
|
||||
Iterator<? extends KeyValueParam> iterator = targetParams.iterator();
|
||||
if (deleteRedundantParam) {
|
||||
while (iterator.hasNext()) {
|
||||
KeyValueParam targetParam = iterator.next();
|
||||
if (targetParam.isValid() && !sourceMaps.keySet().contains(targetParam.getKey())) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Set<String> targetKeys = targetParams.stream()
|
||||
.filter(KeyValueParam::isValid)
|
||||
.map(KeyValueParam::getKey)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// 记住最后一个有效的参数下标
|
||||
int lastIndex = targetParams.size() - 1;
|
||||
for (int i = targetParams.size() - 1; i >= 0; i--) {
|
||||
if (targetParams.get(i).isValid()) {
|
||||
lastIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = sourceParams.size() - 1; i >= 0; i--) {
|
||||
KeyValueParam sourceParam = sourceParams.get(i);
|
||||
if (!sourceParam.isValid()) {
|
||||
continue;
|
||||
}
|
||||
if (!targetKeys.contains(sourceParam.getKey())) {
|
||||
// 如果不包含则添加
|
||||
targetParams.add(lastIndex + 1, (T) sourceParam);
|
||||
}
|
||||
}
|
||||
|
||||
return targetParams;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -112,7 +112,8 @@ public class ApiTestCaseControllerTests extends BaseTest {
|
|||
private static final String BATCH_RUN = "batch/run";
|
||||
private static final String API_CHANGE_CLEAR = "api-change/clear/{0}";
|
||||
private static final String API_CHANGE_IGNORE = "api-change/ignore/{0}?ignore={1}";
|
||||
private static final String API_CHANGE_SYNC = "batch/api-change/sync";
|
||||
private static final String BATCH_API_CHANGE_SYNC = "batch/api-change/sync";
|
||||
private static final String API_CHANGE_SYNC = "api-change/sync";
|
||||
private static final String API_COMPARE = "api/compare/{0}";
|
||||
|
||||
private static final ResultMatcher ERROR_REQUEST_MATCHER = status().is5xxServerError();
|
||||
|
@ -479,13 +480,15 @@ public class ApiTestCaseControllerTests extends BaseTest {
|
|||
updateCase.setId(apiTestCase.getId());
|
||||
apiTestCaseMapper.updateByPrimaryKeySelective(updateCase);
|
||||
this.requestGetWithOk(API_CHANGE_IGNORE, apiTestCase.getId(), true);
|
||||
Assertions.assertFalse(apiTestCaseMapper.selectByPrimaryKey(apiTestCase.getId()).getApiChange());
|
||||
Assertions.assertTrue(apiTestCaseMapper.selectByPrimaryKey(apiTestCase.getId()).getIgnoreApiDiff());
|
||||
Assertions.assertTrue(apiTestCaseMapper.selectByPrimaryKey(apiTestCase.getId()).getIgnoreApiChange());
|
||||
ApiTestCase result = apiTestCaseMapper.selectByPrimaryKey(apiTestCase.getId());
|
||||
Assertions.assertFalse(result.getApiChange());
|
||||
Assertions.assertTrue(result.getIgnoreApiDiff());
|
||||
Assertions.assertTrue(result.getIgnoreApiChange());
|
||||
this.requestGetWithOk(API_CHANGE_IGNORE, apiTestCase.getId(), false);
|
||||
Assertions.assertFalse(apiTestCaseMapper.selectByPrimaryKey(apiTestCase.getId()).getApiChange());
|
||||
Assertions.assertTrue(apiTestCaseMapper.selectByPrimaryKey(apiTestCase.getId()).getIgnoreApiDiff());
|
||||
Assertions.assertFalse(apiTestCaseMapper.selectByPrimaryKey(apiTestCase.getId()).getIgnoreApiChange());
|
||||
result = apiTestCaseMapper.selectByPrimaryKey(apiTestCase.getId());
|
||||
Assertions.assertFalse(result.getApiChange());
|
||||
Assertions.assertTrue(result.getIgnoreApiDiff());
|
||||
Assertions.assertFalse(result.getIgnoreApiChange());
|
||||
|
||||
// @@校验权限
|
||||
requestGetPermissionTest(PermissionConstants.PROJECT_API_DEFINITION_CASE_ADD, API_CHANGE_IGNORE, apiTestCase.getId(), true);
|
||||
|
@ -497,6 +500,25 @@ public class ApiTestCaseControllerTests extends BaseTest {
|
|||
public void batchSyncApiChange() throws Exception {
|
||||
ApiCaseBatchSyncRequest request = new ApiCaseBatchSyncRequest();
|
||||
request.setProjectId(DEFAULT_PROJECT_ID);
|
||||
this.requestPostWithOk(BATCH_API_CHANGE_SYNC, request);
|
||||
|
||||
request.setSelectIds(List.of(apiTestCase.getId()));
|
||||
request.setDeleteRedundantParam(true);
|
||||
this.requestPostWithOk(BATCH_API_CHANGE_SYNC, request);
|
||||
|
||||
ApiTestCase result = apiTestCaseMapper.selectByPrimaryKey(apiTestCase.getId());
|
||||
Assertions.assertFalse(result.getApiChange());
|
||||
|
||||
// @@校验权限
|
||||
requestPostPermissionTest(PermissionConstants.PROJECT_API_DEFINITION_CASE_UPDATE, BATCH_API_CHANGE_SYNC, request);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(4)
|
||||
public void syncApiChange() throws Exception {
|
||||
ApiCaseSyncRequest request = new ApiCaseSyncRequest();
|
||||
request.setId(apiTestCase.getId());
|
||||
request.setApiCaseRequest(JSON.parseObject(ApiDataUtils.toJSONString(new MsHTTPElement())));
|
||||
this.requestPostWithOk(API_CHANGE_SYNC, request);
|
||||
|
||||
// @@校验权限
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
package io.metersphere.api.utils;
|
||||
|
||||
import io.metersphere.api.dto.definition.ApiCaseSyncItemRequest;
|
||||
import io.metersphere.api.dto.definition.ApiCaseSyncRequest;
|
||||
import io.metersphere.api.dto.request.controller.MsLoopController;
|
||||
import io.metersphere.api.dto.request.http.MsHTTPElement;
|
||||
import io.metersphere.api.dto.request.http.MsHeader;
|
||||
import io.metersphere.api.dto.request.http.QueryParam;
|
||||
import io.metersphere.api.dto.request.http.RestParam;
|
||||
import io.metersphere.api.dto.request.http.body.*;
|
||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||
import io.metersphere.project.api.KeyValueParam;
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
import io.metersphere.sdk.util.XMLUtils;
|
||||
|
@ -14,10 +18,7 @@ import org.junit.jupiter.api.Assertions;
|
|||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
|
@ -481,4 +482,337 @@ public class HttpRequestParamDiffUtilsTests {
|
|||
body.getXmlBody().setValue(xmlValue);
|
||||
HttpRequestParamDiffUtils.getCompareHttpElement(msHTTPElement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void syncKeyValueParamDiff() {
|
||||
KeyValueParam kv1 = new KeyValueParam();
|
||||
kv1.setKey("key1");
|
||||
kv1.setValue("value1");
|
||||
KeyValueParam kv2 = new KeyValueParam();
|
||||
kv2.setKey("key2");
|
||||
kv2.setValue("value2");
|
||||
List<KeyValueParam> formDataKVS = List.of(kv1, kv2);
|
||||
|
||||
List<KeyValueParam> result = HttpRequestParamDiffUtils.syncKeyValueParamDiff(true, formDataKVS, null);
|
||||
Assertions.assertEquals(result, formDataKVS);
|
||||
|
||||
result = HttpRequestParamDiffUtils.syncKeyValueParamDiff(true, null, formDataKVS);
|
||||
Assertions.assertEquals(result, List.of());
|
||||
|
||||
result = HttpRequestParamDiffUtils.syncKeyValueParamDiff(false, null, formDataKVS);
|
||||
Assertions.assertEquals(result, formDataKVS);
|
||||
|
||||
KeyValueParam kv3 = new KeyValueParam();
|
||||
kv3.setKey("key3");
|
||||
kv3.setValue("value3");
|
||||
FormDataKV kv4 = new FormDataKV();
|
||||
|
||||
result = HttpRequestParamDiffUtils.syncKeyValueParamDiff(true,
|
||||
new ArrayList<>(List.of(kv1, kv2, kv4)),
|
||||
new ArrayList<>(List.of(kv1, kv3, kv4)));
|
||||
Assertions.assertEquals(result, Arrays.asList(kv1, kv2, kv4));
|
||||
|
||||
result = HttpRequestParamDiffUtils.syncKeyValueParamDiff(false,
|
||||
new ArrayList<>(List.of(kv1, kv2, kv4)),
|
||||
new ArrayList<>(List.of(kv1, kv3, kv4)));
|
||||
Assertions.assertEquals(result, Arrays.asList(kv1, kv3, kv2, kv4));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void syncJsonBodyDiff() {
|
||||
String sourceJsonStr = """
|
||||
{
|
||||
"id": 10,
|
||||
"name": "doggie",
|
||||
"category": {
|
||||
"id": null,
|
||||
"name": "Dogs"
|
||||
},
|
||||
"photoUrls": [
|
||||
"string",
|
||||
{
|
||||
"id": null,
|
||||
"name": "Dogs"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
{
|
||||
"id": 0,
|
||||
"name": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
""";
|
||||
String targetJsonStr = """
|
||||
{
|
||||
"id": 11,
|
||||
"delete": true,
|
||||
"category": "",
|
||||
"photoUrls": [
|
||||
"string",
|
||||
{
|
||||
"id": "aaa",
|
||||
"delete": true
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
{
|
||||
"id": "111",
|
||||
"name": null
|
||||
}
|
||||
]
|
||||
}
|
||||
""";
|
||||
Object sourceJson = JSON.parseObject(sourceJsonStr);
|
||||
Object targetJson = JSON.parseObject(targetJsonStr);
|
||||
Object result = HttpRequestParamDiffUtils.syncJsonBodyDiff(true, sourceJson, targetJson);
|
||||
Object assertionJson = JSON.parseObject("""
|
||||
{
|
||||
"id": 11,
|
||||
"name": "doggie",
|
||||
"category": {
|
||||
"id": null,
|
||||
"name": "Dogs"
|
||||
},
|
||||
"photoUrls": [
|
||||
"string",
|
||||
{
|
||||
"id": null,
|
||||
"name": "Dogs"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
{
|
||||
"id": 0,
|
||||
"name": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
""");
|
||||
Assertions.assertEquals(result, assertionJson);
|
||||
|
||||
JsonBody sourceJsonBody = new JsonBody();
|
||||
sourceJsonBody.setJsonValue(sourceJsonStr);
|
||||
JsonBody tartJsonBody = new JsonBody();
|
||||
tartJsonBody.setJsonValue(targetJsonStr);
|
||||
JsonBody resultBody = HttpRequestParamDiffUtils.syncJsonBodyDiff(true, sourceJsonBody, tartJsonBody);
|
||||
Assertions.assertEquals(assertionJson, JSON.parseObject(resultBody.getJsonValue()));
|
||||
|
||||
sourceJson = JSON.parseObject(sourceJsonStr);
|
||||
targetJson = JSON.parseObject(targetJsonStr);
|
||||
result = HttpRequestParamDiffUtils.syncJsonBodyDiff(false, sourceJson, targetJson);
|
||||
assertionJson = JSON.parseObject("""
|
||||
{
|
||||
"id": 11,
|
||||
"name": "doggie",
|
||||
"delete": true,
|
||||
"category": {
|
||||
"id": null,
|
||||
"name": "Dogs"
|
||||
},
|
||||
"photoUrls": [
|
||||
"string",
|
||||
{
|
||||
"id": "aaa",
|
||||
"name": "Dogs",
|
||||
"delete": true
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
{
|
||||
"id": 0,
|
||||
"name": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
""");
|
||||
Assertions.assertEquals(result, assertionJson);
|
||||
|
||||
sourceJsonBody = new JsonBody();
|
||||
sourceJsonBody.setJsonValue(sourceJsonStr);
|
||||
tartJsonBody = new JsonBody();
|
||||
tartJsonBody.setJsonValue(targetJsonStr);
|
||||
resultBody = HttpRequestParamDiffUtils.syncJsonBodyDiff(false, sourceJsonBody, tartJsonBody);
|
||||
Assertions.assertEquals(assertionJson, JSON.parseObject(resultBody.getJsonValue()));
|
||||
|
||||
resultBody = HttpRequestParamDiffUtils.syncJsonBodyDiff(false, null, tartJsonBody);
|
||||
Assertions.assertEquals(resultBody, tartJsonBody);
|
||||
|
||||
resultBody = HttpRequestParamDiffUtils.syncJsonBodyDiff(true, null, tartJsonBody);
|
||||
Assertions.assertEquals(resultBody, new JsonBody());
|
||||
|
||||
resultBody = HttpRequestParamDiffUtils.syncJsonBodyDiff(true, sourceJsonBody, null);
|
||||
Assertions.assertEquals(resultBody, sourceJsonBody);
|
||||
|
||||
// 解析异常
|
||||
sourceJsonBody.setJsonValue("ddd");
|
||||
resultBody = HttpRequestParamDiffUtils.syncJsonBodyDiff(true, sourceJsonBody, sourceJsonBody);
|
||||
Assertions.assertEquals(resultBody, sourceJsonBody);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void syncXmlBodyDiff() throws Exception {
|
||||
String sourceXmlStr = """
|
||||
<project>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
</project>
|
||||
""";
|
||||
String targetXmlStr = """
|
||||
<project>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<delete>true</delete>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<relativePath/>
|
||||
<delete>true</delete>
|
||||
</parent>
|
||||
</project>
|
||||
""";
|
||||
Element sourceElement = XMLUtils.stringToDocument(sourceXmlStr).getRootElement();
|
||||
Element targetElement = XMLUtils.stringToDocument(targetXmlStr).getRootElement();
|
||||
HttpRequestParamDiffUtils.syncXmlBodyDiff(true, null, sourceElement);
|
||||
HttpRequestParamDiffUtils.syncXmlBodyDiff(true, sourceElement, null);
|
||||
Element result = HttpRequestParamDiffUtils.syncXmlBodyDiff(true, sourceElement, targetElement);
|
||||
String resultStr = HttpRequestParamDiffUtils.parseElementToString(result);
|
||||
String assertionStr = HttpRequestParamDiffUtils.parseElementToString(XMLUtils.stringToDocument("""
|
||||
<project>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
\s
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<relativePath/>
|
||||
\s
|
||||
<artifactId>spring-boot-starter-parent</artifactId></parent>
|
||||
</project>
|
||||
""").getRootElement());
|
||||
Assertions.assertEquals(resultStr, assertionStr);
|
||||
|
||||
XmlBody sourceXmlBody = new XmlBody();
|
||||
XmlBody tartgetXmlBody = new XmlBody();
|
||||
sourceXmlBody.setValue(sourceXmlStr);
|
||||
tartgetXmlBody.setValue(targetXmlStr);
|
||||
XmlBody resultBody = HttpRequestParamDiffUtils.syncXmlBodyDiff(true, sourceXmlBody, tartgetXmlBody);
|
||||
Assertions.assertEquals(assertionStr, resultBody.getValue());
|
||||
|
||||
sourceElement = XMLUtils.stringToDocument(sourceXmlStr).getRootElement();
|
||||
targetElement = XMLUtils.stringToDocument(targetXmlStr).getRootElement();
|
||||
result = HttpRequestParamDiffUtils.syncXmlBodyDiff(false, sourceElement, targetElement);
|
||||
resultStr = HttpRequestParamDiffUtils.parseElementToString(result);
|
||||
assertionStr = HttpRequestParamDiffUtils.parseElementToString(XMLUtils.stringToDocument("""
|
||||
<project>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<delete>true</delete>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<relativePath/>
|
||||
<delete>true</delete>
|
||||
<artifactId>spring-boot-starter-parent</artifactId></parent>
|
||||
</project>
|
||||
""").getRootElement());
|
||||
Assertions.assertEquals(resultStr, assertionStr);
|
||||
|
||||
// 格式错误
|
||||
tartgetXmlBody.setValue("dddd");
|
||||
resultBody = HttpRequestParamDiffUtils.syncXmlBodyDiff(true, sourceXmlBody, tartgetXmlBody);
|
||||
Assertions.assertEquals(resultBody, tartgetXmlBody);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void syncBodyDiff() {
|
||||
|
||||
Body sourceBody = new Body();
|
||||
Body targetBody = new Body();
|
||||
|
||||
Body result = HttpRequestParamDiffUtils.syncBodyDiff(true, null, targetBody);
|
||||
Assertions.assertEquals(result, null);
|
||||
|
||||
result = HttpRequestParamDiffUtils.syncBodyDiff(true, sourceBody, null);
|
||||
Assertions.assertEquals(result, sourceBody);
|
||||
|
||||
sourceBody.setBodyType(Body.BodyType.FORM_DATA.name());
|
||||
targetBody.setBodyType(Body.BodyType.WWW_FORM.name());
|
||||
result = HttpRequestParamDiffUtils.syncBodyDiff(true, sourceBody, targetBody);
|
||||
Assertions.assertEquals(result, sourceBody);
|
||||
|
||||
sourceBody.setBodyType(Body.BodyType.RAW.name());
|
||||
targetBody.setBodyType(Body.BodyType.RAW.name());
|
||||
result = HttpRequestParamDiffUtils.syncBodyDiff(true, sourceBody, targetBody);
|
||||
Assertions.assertEquals(result, targetBody);
|
||||
|
||||
sourceBody.setBodyType(Body.BodyType.BINARY.name());
|
||||
targetBody.setBodyType(Body.BodyType.BINARY.name());
|
||||
result = HttpRequestParamDiffUtils.syncBodyDiff(true, sourceBody, targetBody);
|
||||
Assertions.assertEquals(result, targetBody);
|
||||
|
||||
sourceBody.setBodyType(Body.BodyType.FORM_DATA.name());
|
||||
targetBody.setBodyType(Body.BodyType.FORM_DATA.name());
|
||||
sourceBody.setFormDataBody(new FormDataBody());
|
||||
targetBody.setFormDataBody(new FormDataBody());
|
||||
FormDataKV formDataKV = new FormDataKV();
|
||||
formDataKV.setKey("key1");
|
||||
formDataKV.setValue("value1");
|
||||
sourceBody.getFormDataBody().getFormValues().add(formDataKV);
|
||||
result = HttpRequestParamDiffUtils.syncBodyDiff(true, sourceBody, targetBody);
|
||||
Assertions.assertEquals(result.getFormDataBody(), sourceBody.getFormDataBody());
|
||||
|
||||
sourceBody.setBodyType(Body.BodyType.WWW_FORM.name());
|
||||
targetBody.setBodyType(Body.BodyType.WWW_FORM.name());
|
||||
sourceBody.setWwwFormBody(new WWWFormBody());
|
||||
targetBody.setWwwFormBody(new WWWFormBody());
|
||||
WWWFormKV wwwFormKV = new WWWFormKV();
|
||||
wwwFormKV.setKey("key1");
|
||||
wwwFormKV.setValue("value1");
|
||||
sourceBody.getWwwFormBody().getFormValues().add(wwwFormKV);
|
||||
result = HttpRequestParamDiffUtils.syncBodyDiff(true, sourceBody, targetBody);
|
||||
Assertions.assertEquals(result.getWwwFormBody(), sourceBody.getWwwFormBody());
|
||||
|
||||
sourceBody.setBodyType(Body.BodyType.JSON.name());
|
||||
targetBody.setBodyType(Body.BodyType.JSON.name());
|
||||
sourceBody.setJsonBody(new JsonBody());
|
||||
targetBody.setJsonBody(new JsonBody());
|
||||
sourceBody.getJsonBody().setJsonValue("""
|
||||
{"id1":""}
|
||||
""");
|
||||
result = HttpRequestParamDiffUtils.syncBodyDiff(true, sourceBody, targetBody);
|
||||
Assertions.assertEquals(result.getJsonBody(), sourceBody.getJsonBody());
|
||||
|
||||
sourceBody.setBodyType(Body.BodyType.XML.name());
|
||||
targetBody.setBodyType(Body.BodyType.XML.name());
|
||||
sourceBody.setXmlBody(new XmlBody());
|
||||
targetBody.setXmlBody(new XmlBody());
|
||||
sourceBody.getXmlBody().setValue("""
|
||||
<a></a>
|
||||
""");
|
||||
result = HttpRequestParamDiffUtils.syncBodyDiff(true, sourceBody, targetBody);
|
||||
Assertions.assertEquals(result.getXmlBody(), sourceBody.getXmlBody());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void syncRequestDiff() {
|
||||
MsHTTPElement sourceElement = new MsHTTPElement();
|
||||
MsHTTPElement targetElement = new MsHTTPElement();
|
||||
|
||||
ApiCaseSyncRequest request = new ApiCaseSyncRequest();
|
||||
ApiCaseSyncItemRequest syncItems = new ApiCaseSyncItemRequest();
|
||||
request.setSyncItems(syncItems);
|
||||
request.setDeleteRedundantParam(true);
|
||||
|
||||
AbstractMsTestElement resultTestElement = HttpRequestParamDiffUtils.syncRequestDiff(request, sourceElement, targetElement);
|
||||
Assertions.assertEquals(resultTestElement, targetElement);
|
||||
|
||||
syncItems.setBody(false);
|
||||
syncItems.setQuery(false);
|
||||
syncItems.setRest(false);
|
||||
syncItems.setHeader(false);
|
||||
resultTestElement = HttpRequestParamDiffUtils.syncRequestDiff(request, sourceElement, targetElement);
|
||||
Assertions.assertEquals(resultTestElement, targetElement);
|
||||
|
||||
resultTestElement = HttpRequestParamDiffUtils.syncRequestDiff(request, new MsLoopController(), targetElement);
|
||||
Assertions.assertEquals(resultTestElement, targetElement);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue