diff --git a/arex-schedule-web-api/pom.xml b/arex-schedule-web-api/pom.xml index 6b22de85..c22564f1 100644 --- a/arex-schedule-web-api/pom.xml +++ b/arex-schedule-web-api/pom.xml @@ -136,7 +136,7 @@ arex-schedule-parent com.arextest - 1.2.17 + 1.2.18 @@ -338,5 +338,5 @@ - 1.2.17 + 1.2.18 \ No newline at end of file diff --git a/arex-schedule-web-api/src/main/java/com/arextest/schedule/client/HttpWepServiceApiClient.java b/arex-schedule-web-api/src/main/java/com/arextest/schedule/client/HttpWepServiceApiClient.java index 3e70cbff..c2aa2782 100644 --- a/arex-schedule-web-api/src/main/java/com/arextest/schedule/client/HttpWepServiceApiClient.java +++ b/arex-schedule-web-api/src/main/java/com/arextest/schedule/client/HttpWepServiceApiClient.java @@ -1,6 +1,7 @@ package com.arextest.schedule.client; import static com.arextest.schedule.common.CommonConstant.URL; +import static org.springframework.http.HttpHeaders.CONTENT_TYPE; import com.arextest.schedule.utils.SSLUtils; import com.fasterxml.jackson.databind.ObjectMapper; @@ -74,6 +75,7 @@ public final class HttpWepServiceApiClient { @Autowired(required = false) private List clientHttpRequestInterceptors; + private static final String ZSTD_JSON_CONTENT_TYPE = "application/zstd-json;charset=UTF-8"; @PostConstruct private void initTemplate() { @@ -250,6 +252,21 @@ public ResponseEntity retryJsonPost(String url, } } + public TResponse retryZstdJsonPost(String url, TRequest request, + Class responseType) { + Map headers = Maps.newHashMapWithExpectedSize(1); + headers.put(HttpHeaders.CONTENT_TYPE, ZSTD_JSON_CONTENT_TYPE); + + try { + return retryTemplate.execute(retryCallback -> { + retryCallback.setAttribute(URL, url); + return restTemplate.postForObject(url, wrapJsonContentType(request, headers), responseType); + }); + } catch (Exception e) { + return null; + } + } + @SuppressWarnings("unchecked") private HttpEntity wrapJsonContentType(TRequest request) { HttpEntity httpJsonEntity; @@ -271,7 +288,9 @@ private HttpEntity wrapJsonContentType(TRequest request, httpJsonEntity = (HttpEntity) request; } else { HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); + if (!extraHeaders.containsKey(CONTENT_TYPE)) { + headers.setContentType(MediaType.APPLICATION_JSON); + } headers.setAll(extraHeaders); httpJsonEntity = new HttpEntity<>(request, headers); } diff --git a/arex-schedule-web-api/src/main/java/com/arextest/schedule/client/ZstdJacksonMessageConverter.java b/arex-schedule-web-api/src/main/java/com/arextest/schedule/client/ZstdJacksonMessageConverter.java index 4c4cb7ce..5db1b764 100644 --- a/arex-schedule-web-api/src/main/java/com/arextest/schedule/client/ZstdJacksonMessageConverter.java +++ b/arex-schedule-web-api/src/main/java/com/arextest/schedule/client/ZstdJacksonMessageConverter.java @@ -29,7 +29,7 @@ public ZstdJacksonMessageConverter() { @Override protected boolean supports(Class clazz) { - return true; + return !(clazz == byte[].class || clazz.isPrimitive()); } @Override @@ -41,6 +41,6 @@ protected Object readInternal(Class clazz, HttpInputMessage inputMessage) thr @Override protected void writeInternal(Object o, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { - zstdJacksonSerializer.serializeTo(o, outputMessage.getBody()); + outputMessage.getBody().write(zstdJacksonSerializer.serialize(o)); } } \ No newline at end of file diff --git a/arex-schedule-web-api/src/main/java/com/arextest/schedule/common/JsonUtils.java b/arex-schedule-web-api/src/main/java/com/arextest/schedule/common/JsonUtils.java index f9f9ede4..04f248bf 100644 --- a/arex-schedule-web-api/src/main/java/com/arextest/schedule/common/JsonUtils.java +++ b/arex-schedule-web-api/src/main/java/com/arextest/schedule/common/JsonUtils.java @@ -22,11 +22,20 @@ public static T byteToObject(byte[] bytes, Class tClass) { return null; } + public static T jsonStringToObject(String string, Class tClass) { + try { + return objectMapper.readValue(string, tClass); + } catch (IOException e) { + LOGGER.error("jsonStringToObject error:{}", e.getMessage(), e); + } + return null; + } + public static String objectToJsonString(Object value) { try { return objectMapper.writeValueAsString(value); } catch (IOException e) { - LOGGER.error("byteToObject error:{}", e.getMessage(), e); + LOGGER.error("objectToJsonString error:{}", e.getMessage(), e); } return StringUtils.EMPTY; } diff --git a/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/CategoryComparisonHolder.java b/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/CategoryComparisonHolder.java index 17a1b2b8..80317ddb 100644 --- a/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/CategoryComparisonHolder.java +++ b/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/CategoryComparisonHolder.java @@ -1,6 +1,7 @@ package com.arextest.schedule.comparer; import java.util.List; +import lombok.AllArgsConstructor; import lombok.Data; /** @@ -11,6 +12,22 @@ public class CategoryComparisonHolder { private String categoryName; + /** + * Need to match the comparison relationship + */ private List record; private List replayResult; + + private boolean needMatch; + /** + * Not need to match the comparison relationship + */ + private CompareResultItem compareResultItem; + + @Data + @AllArgsConstructor + public static class CompareResultItem { + CompareItem recordItem; + CompareItem replayItem; + } } \ No newline at end of file diff --git a/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/converter/CompareItemConvertFactory.java b/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/converter/CompareItemConvertFactory.java new file mode 100644 index 00000000..4970683d --- /dev/null +++ b/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/converter/CompareItemConvertFactory.java @@ -0,0 +1,26 @@ +package com.arextest.schedule.comparer.converter; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; +import javax.annotation.Resource; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class CompareItemConvertFactory { + private final Map categoryConverters; + @Resource + private CompareItemConverter defaultCompareItemConverterImpl; + + public CompareItemConvertFactory(@Autowired List converters) { + this.categoryConverters = converters.stream().filter(c -> StringUtils.isNotBlank(c.getCategoryName())) + .collect(Collectors.toMap(CompareItemConverter::getCategoryName, Function.identity())); + } + + public CompareItemConverter getConvert(String categoryName) { + return categoryConverters.getOrDefault(categoryName, defaultCompareItemConverterImpl); + } +} diff --git a/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/converter/CompareItemConverter.java b/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/converter/CompareItemConverter.java new file mode 100644 index 00000000..e872bf30 --- /dev/null +++ b/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/converter/CompareItemConverter.java @@ -0,0 +1,29 @@ +package com.arextest.schedule.comparer.converter; + +import com.arextest.model.mock.AREXMocker; +import com.arextest.model.replay.CompareRelationResult; +import com.arextest.schedule.comparer.CompareItem; + +public interface CompareItemConverter { + String DEFAULT_CATEGORY_NAME = "default"; + + default String getCategoryName() { + return DEFAULT_CATEGORY_NAME; + } + + /** + * Convert mocker to compare item, The agent handles the compatibility needs before the match + * @param mocker + * @return + */ + CompareItem convert(AREXMocker mocker); + + /** + * Convert relation result to compare item + * @param relationResult + * @param recordCompareItem + * @return + */ + CompareItem convert(CompareRelationResult relationResult, boolean recordCompareItem); + +} diff --git a/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/converter/impl/DatabaseCompareItemConverterImpl.java b/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/converter/impl/DatabaseCompareItemConverterImpl.java new file mode 100644 index 00000000..d01f33b2 --- /dev/null +++ b/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/converter/impl/DatabaseCompareItemConverterImpl.java @@ -0,0 +1,92 @@ +package com.arextest.schedule.comparer.converter.impl; + +import com.arextest.model.constants.MockAttributeNames; +import com.arextest.model.mock.AREXMocker; +import com.arextest.model.mock.MockCategoryType; +import com.arextest.model.mock.Mocker.Target; +import com.arextest.model.replay.CompareRelationResult; +import com.arextest.schedule.common.JsonUtils; +import com.arextest.schedule.comparer.CompareItem; +import com.arextest.schedule.comparer.converter.CompareItemConverter; +import com.arextest.schedule.comparer.impl.PrepareCompareItemBuilder.CompareItemImpl; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; +import java.util.Map; +import java.util.Map.Entry; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +/** + * @author xinyuan_wang. + * @create 2024/9/2 16:46 + */ +@Slf4j +@Component +public class DatabaseCompareItemConverterImpl implements CompareItemConverter { + + @Override + public String getCategoryName() { + return MockCategoryType.DATABASE.getName(); + } + + @Override + public CompareItem convert(AREXMocker mocker) { + MockCategoryType categoryType = mocker.getCategoryType(); + String operationKey = getOperationName(mocker.getTargetRequest(), mocker.getOperationName()); + return new CompareItemImpl(operationKey, buildAttributes(mocker.getTargetRequest()).toString(), + mocker.getId(), mocker.getCreationTime(), categoryType.isEntryPoint()); + } + + @Override + public CompareItem convert(CompareRelationResult relationResult, boolean recordCompareItem) { + String message = recordCompareItem ? relationResult.getRecordMessage() : relationResult.getReplayMessage(); + long createTime = recordCompareItem ? relationResult.getRecordTime() : relationResult.getReplayTime(); + return new CompareItemImpl(relationResult.getOperationName(), processMessage(message), null, + createTime, relationResult.getCategoryType().isEntryPoint()); + } + + private String processMessage(String message) { + if (StringUtils.isBlank(message)) { + return message; + } + + Target target = JsonUtils.jsonStringToObject(message, Target.class); + if (target != null) { + message = buildAttributes(target).toString(); + } + return message; + } + + private ObjectNode buildAttributes(Target target) { + ObjectNode obj = JsonNodeFactory.instance.objectNode(); + if (target == null) { + return obj; + } + Map attributes = target.getAttributes(); + if (attributes != null) { + for (Entry entry : attributes.entrySet()) { + Object value = entry.getValue(); + if (value instanceof String) { + obj.put(entry.getKey(), (String) value); + } else { + obj.putPOJO(entry.getKey(), value); + } + } + } + if (StringUtils.isNotEmpty(target.getBody())) { + obj.put("body", target.getBody()); + } + return obj; + } + + private String getOperationName(Target target, String operationName) { + // The "@" in the operationName of DATABASE indicates that the SQL statement has been parsed and returned directly. + String compareOperationName = StringUtils.contains(operationName, "@") ? operationName + : target.attributeAsString(MockAttributeNames.DB_NAME); + if (StringUtils.isNotBlank(compareOperationName)) { + return compareOperationName; + } + return operationName; + } +} diff --git a/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/converter/impl/DefaultCompareItemConverterImpl.java b/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/converter/impl/DefaultCompareItemConverterImpl.java new file mode 100644 index 00000000..fbd1c731 --- /dev/null +++ b/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/converter/impl/DefaultCompareItemConverterImpl.java @@ -0,0 +1,46 @@ +package com.arextest.schedule.comparer.converter.impl; + +import com.arextest.model.mock.AREXMocker; +import com.arextest.model.mock.MockCategoryType; +import com.arextest.model.replay.CompareRelationResult; +import com.arextest.schedule.comparer.CompareItem; +import com.arextest.schedule.comparer.converter.CompareItemConverter; +import com.arextest.schedule.comparer.impl.PrepareCompareItemBuilder.CompareItemImpl; +import java.util.Objects; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * @author xinyuan_wang. + * @create 2024/9/2 16:46 + */ +@Slf4j +@Component +public class DefaultCompareItemConverterImpl implements CompareItemConverter { + + @Override + public CompareItem convert(AREXMocker mocker) { + MockCategoryType categoryType = mocker.getCategoryType(); + String operationKey = mocker.getOperationName(); + long createTime = mocker.getCreationTime(); + String body; + String compareKey = mocker.getId(); + boolean entryPointCategory = false; + if (categoryType.isEntryPoint()) { + body = Objects.isNull(mocker.getTargetResponse()) ? null + : mocker.getTargetResponse().getBody(); + compareKey = null; + entryPointCategory = true; + } else { + body = Objects.isNull(mocker.getTargetRequest()) ? null + : mocker.getTargetRequest().getBody(); + } + return new CompareItemImpl(operationKey, body, compareKey, createTime, entryPointCategory); + } + + @Override + public CompareItem convert(CompareRelationResult relationResult, boolean recordCompareItem) { + return new CompareItemImpl(relationResult, recordCompareItem); + } + +} diff --git a/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/converter/impl/RedisCompareItemConverterImpl.java b/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/converter/impl/RedisCompareItemConverterImpl.java new file mode 100644 index 00000000..9bf0c0ad --- /dev/null +++ b/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/converter/impl/RedisCompareItemConverterImpl.java @@ -0,0 +1,54 @@ +package com.arextest.schedule.comparer.converter.impl; + +import com.arextest.model.constants.MockAttributeNames; +import com.arextest.model.mock.AREXMocker; +import com.arextest.model.mock.MockCategoryType; +import com.arextest.model.mock.Mocker.Target; +import com.arextest.model.replay.CompareRelationResult; +import com.arextest.schedule.comparer.CompareItem; +import com.arextest.schedule.comparer.converter.CompareItemConverter; +import com.arextest.schedule.comparer.impl.PrepareCompareItemBuilder.CompareItemImpl; +import java.util.Objects; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +/** + * @author xinyuan_wang. + * @create 2024/9/2 16:46 + */ +@Slf4j +@Component +public class RedisCompareItemConverterImpl implements CompareItemConverter { + + @Override + public String getCategoryName() { + return MockCategoryType.REDIS.getName(); + } + + @Override + public CompareItem convert(AREXMocker mocker) { + MockCategoryType categoryType = mocker.getCategoryType(); + String operationKey = getOperationName(mocker.getTargetRequest(), mocker.getOperationName()); + String compareMessage = Objects.isNull(mocker.getTargetRequest()) ? null + : mocker.getTargetRequest().getBody(); + + return new CompareItemImpl(operationKey, compareMessage, mocker.getId(), + mocker.getCreationTime(), categoryType.isEntryPoint()); + } + @Override + public CompareItem convert(CompareRelationResult relationResult, boolean recordCompareItem) { + String message = recordCompareItem ? relationResult.getRecordMessage() : relationResult.getReplayMessage(); + long createTime = recordCompareItem ? relationResult.getRecordTime() : relationResult.getReplayTime(); + return new CompareItemImpl(relationResult.getOperationName(), message, null, + createTime, relationResult.getCategoryType().isEntryPoint()); + } + + private String getOperationName(Target target, String operationName) { + String compareOperationName = target.attributeAsString(MockAttributeNames.CLUSTER_NAME); + if (StringUtils.isNotBlank(compareOperationName)) { + return compareOperationName; + } + return operationName; + } +} diff --git a/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/impl/DefaultReplayResultComparer.java b/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/impl/DefaultReplayResultComparer.java index 9adba651..90791b15 100644 --- a/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/impl/DefaultReplayResultComparer.java +++ b/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/impl/DefaultReplayResultComparer.java @@ -6,6 +6,7 @@ import com.arextest.diff.sdk.CompareSDK; import com.arextest.model.mock.MockCategoryType; import com.arextest.schedule.comparer.CategoryComparisonHolder; +import com.arextest.schedule.comparer.CategoryComparisonHolder.CompareResultItem; import com.arextest.schedule.comparer.CompareConfigService; import com.arextest.schedule.comparer.CompareItem; import com.arextest.schedule.comparer.CompareService; @@ -162,10 +163,39 @@ public List doContentCompare(ReplayActionCaseItem caseItem, } /** - * compare recording and replay data. 1. record and replay data through compareKey. + * compare recording and replay data. */ private List compareReplayResult(CategoryComparisonHolder bindHolder, ReplayActionCaseItem caseItem, ComparisonInterfaceConfig operationConfig) { + if (bindHolder.isNeedMatch()) { + return matchCompareReplayResults(bindHolder, caseItem, operationConfig); + } + + return getReplayCompareResults(bindHolder, caseItem, operationConfig); + } + + private List getReplayCompareResults(CategoryComparisonHolder bindHolder, + ReplayActionCaseItem caseItem, ComparisonInterfaceConfig operationConfig) { + CompareResultItem item = bindHolder.getCompareResultItem(); + if (item == null) { + return Collections.emptyList(); + } + + List compareResults = new ArrayList<>(); + compareResults.add(compareRecordAndResult(operationConfig, caseItem, bindHolder.getCategoryName(), + item.getReplayItem(), item.getRecordItem())); + return compareResults; + } + + /** + * record and replay data through compareKey. + * @param bindHolder + * @param caseItem + * @param operationConfig + * @return + */ + private List matchCompareReplayResults(CategoryComparisonHolder bindHolder, + ReplayActionCaseItem caseItem, ComparisonInterfaceConfig operationConfig) { List compareResults = new ArrayList<>(); List recordResults = bindHolder.getRecord(); List replayResults = bindHolder.getReplayResult(); diff --git a/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/impl/PrepareCompareItemBuilder.java b/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/impl/PrepareCompareItemBuilder.java index c918dbbc..5d679208 100644 --- a/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/impl/PrepareCompareItemBuilder.java +++ b/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/impl/PrepareCompareItemBuilder.java @@ -1,16 +1,11 @@ package com.arextest.schedule.comparer.impl; -import com.arextest.model.constants.MockAttributeNames; import com.arextest.model.mock.AREXMocker; -import com.arextest.model.mock.MockCategoryType; -import com.arextest.model.mock.Mocker.Target; +import com.arextest.model.replay.CompareRelationResult; import com.arextest.schedule.comparer.CompareItem; -import com.fasterxml.jackson.databind.node.JsonNodeFactory; -import com.fasterxml.jackson.databind.node.ObjectNode; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; -import org.apache.commons.lang3.StringUtils; +import com.arextest.schedule.comparer.converter.CompareItemConvertFactory; +import com.arextest.schedule.comparer.converter.CompareItemConverter; +import javax.annotation.Resource; import org.springframework.stereotype.Component; /** @@ -18,67 +13,22 @@ * @since 2021/11/23 */ @Component -final class PrepareCompareItemBuilder { +public class PrepareCompareItemBuilder { - CompareItem build(AREXMocker instance) { - MockCategoryType categoryType = instance.getCategoryType(); - String operationKey = operationName(categoryType, instance.getTargetRequest(), instance.getOperationName()); - if (StringUtils.isEmpty(operationKey)) { - operationKey = instance.getOperationName(); - } - long createTime = instance.getCreationTime(); - String body; - String compareKey = instance.getId(); - boolean entryPointCategory = false; - if (categoryType.isEntryPoint()) { - body = Objects.isNull(instance.getTargetResponse()) ? null - : instance.getTargetResponse().getBody(); - compareKey = null; - entryPointCategory = true; - } else if (Objects.equals(categoryType.getName(), MockCategoryType.DATABASE.getName())) { - body = this.buildAttributes(instance.getTargetRequest()).toString(); - } else { - body = Objects.isNull(instance.getTargetRequest()) ? null - : instance.getTargetRequest().getBody(); - } - return new CompareItemImpl(operationKey, body, compareKey, createTime, entryPointCategory); - } + @Resource + private CompareItemConvertFactory factory; - private String operationName(MockCategoryType categoryType, Target target, String operationName) { - if (Objects.equals(categoryType, MockCategoryType.DATABASE)) { - // The "@" in the operationName of DATABASE indicates that the SQL statement has been parsed and returned directly. - return StringUtils.contains(operationName, "@") ? operationName : target.attributeAsString(MockAttributeNames.DB_NAME); - } - if (Objects.equals(categoryType, MockCategoryType.REDIS)) { - return target.attributeAsString(MockAttributeNames.CLUSTER_NAME); - } - return operationName; + CompareItem build(AREXMocker mocker) { + CompareItemConverter converter = factory.getConvert(mocker.getCategoryType().getName()); + return converter.convert(mocker); } - private ObjectNode buildAttributes(Target target) { - ObjectNode obj = JsonNodeFactory.instance.objectNode(); - if (target == null) { - return obj; - } - Map attributes = target.getAttributes(); - if (attributes != null) { - for (Entry entry : attributes.entrySet()) { - Object value = entry.getValue(); - if (value instanceof String) { - obj.put(entry.getKey(), (String) value); - } else { - obj.putPOJO(entry.getKey(), value); - } - } - } - if (StringUtils.isNotEmpty(target.getBody())) { - obj.put("body", target.getBody()); - } - return obj; + public CompareItem build(CompareRelationResult result, boolean recordCompareItem) { + CompareItemConverter converter = factory.getConvert(result.getCategoryType().getName()); + return converter.convert(result, recordCompareItem); } - private final static class CompareItemImpl implements CompareItem { - + public final static class CompareItemImpl implements CompareItem { private final String compareMessage; private final String compareOperation; private final String compareService; @@ -86,11 +36,20 @@ private final static class CompareItemImpl implements CompareItem { private final long createTime; private final boolean entryPointCategory; - private CompareItemImpl(String compareOperation, String compareMessage, String compareKey, + public CompareItemImpl(String compareOperation, String compareMessage, String compareKey, long createTime, boolean entryPointCategory) { this(compareOperation, compareMessage, null, compareKey, createTime, entryPointCategory); } + public CompareItemImpl(CompareRelationResult result, boolean recordCompareItem) { + this.compareOperation = result.getOperationName(); + this.compareService = null; + this.compareKey = null; + this.entryPointCategory = result.getCategoryType().isEntryPoint(); + this.compareMessage = recordCompareItem ? result.getRecordMessage() : result.getReplayMessage(); + this.createTime = recordCompareItem ? result.getRecordTime() : result.getReplayTime(); + } + private CompareItemImpl(String compareOperation, String compareMessage, String compareService, String compareKey, long createTime, boolean entryPointCategory) { diff --git a/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/impl/PrepareCompareSourceRemoteLoader.java b/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/impl/PrepareCompareSourceRemoteLoader.java index 844743bc..d128e8b5 100644 --- a/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/impl/PrepareCompareSourceRemoteLoader.java +++ b/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/impl/PrepareCompareSourceRemoteLoader.java @@ -1,13 +1,14 @@ package com.arextest.schedule.comparer.impl; +import com.arextest.model.replay.CompareRelationResult; import com.arextest.model.mock.AREXMocker; import com.arextest.model.mock.MockCategoryType; import com.arextest.model.replay.QueryReplayResultRequestType; import com.arextest.model.replay.QueryReplayResultResponseType; import com.arextest.model.replay.holder.ListResultHolder; -import com.arextest.model.response.ResponseStatusType; import com.arextest.schedule.client.HttpWepServiceApiClient; import com.arextest.schedule.comparer.CategoryComparisonHolder; +import com.arextest.schedule.comparer.CategoryComparisonHolder.CompareResultItem; import com.arextest.schedule.comparer.CompareItem; import com.arextest.schedule.model.ReplayActionCaseItem; import com.arextest.schedule.serialization.ZstdJacksonSerializer; @@ -78,38 +79,46 @@ private QueryReplayResultResponseType remoteLoad(String replayId, String resultI QueryReplayResultRequestType resultRequest = new QueryReplayResultRequestType(); resultRequest.setRecordId(replayId); resultRequest.setReplayResultId(resultId); - return httpWepServiceApiClient.retryJsonPost(replayResultUrl, resultRequest, - QueryReplayResultResponseType.class); + return httpWepServiceApiClient.retryZstdJsonPost(replayResultUrl, + resultRequest, QueryReplayResultResponseType.class); } + /** + * Compatible logic. + * The subsequent agent will match the packets and does not need to be processed in the schedule. + * @param replayResultResponseType + * @return + */ private List decodeResult( QueryReplayResultResponseType replayResultResponseType) { - if (replayResultResponseType == null) { + if (replayResultResponseType == null || + replayResultResponseType.getResponseStatusType() == null || + replayResultResponseType.getResponseStatusType().hasError() || + Boolean.TRUE.equals(replayResultResponseType.getInvalidResult())) { + LOGGER.warn("failed to get replay result because of invalid case"); return Collections.emptyList(); } - ResponseStatusType responseStatusType = replayResultResponseType.getResponseStatusType(); - if (responseStatusType == null) { - return Collections.emptyList(); - } - if (responseStatusType.hasError()) { - LOGGER.warn("query replay result has error response : {}", responseStatusType); - return Collections.emptyList(); - } - if (Boolean.TRUE.equals(replayResultResponseType.getInvalidResult())) { - LOGGER.warn("query replay result has invalid result: get data failed from storage"); - return Collections.emptyList(); - } + + // Use needMatch to determine whether to adopt new logic + return Boolean.TRUE.equals(replayResultResponseType.getNeedMatch()) ? + processMatchNeeded(replayResultResponseType) : processMatchNotNeeded(replayResultResponseType); + } + + /** + * Processing of messages that require matching relationships that need to be compared + * @param replayResultResponseType + * @return + */ + private List processMatchNeeded(QueryReplayResultResponseType replayResultResponseType) { List resultHolderList = replayResultResponseType.getResultHolderList(); if (CollectionUtils.isEmpty(resultHolderList)) { LOGGER.warn("query replay result has empty size"); return Collections.emptyList(); } - List decodedListResult = new ArrayList<>(resultHolderList.size()); - MockCategoryType categoryType; - for (int i = 0; i < resultHolderList.size(); i++) { - ListResultHolder stringListResultHolder = resultHolderList.get(i); - categoryType = stringListResultHolder.getCategoryType(); + List decodedListResult = new ArrayList<>(resultHolderList.size()); + for (ListResultHolder stringListResultHolder : resultHolderList) { + MockCategoryType categoryType = stringListResultHolder.getCategoryType(); if (categoryType == null || categoryType.isSkipComparison()) { continue; } @@ -117,19 +126,56 @@ private List decodeResult( CategoryComparisonHolder resultHolder = new CategoryComparisonHolder(); resultHolder.setCategoryName(categoryType.getName()); decodedListResult.add(resultHolder); + List recordList = zstdDeserialize(stringListResultHolder.getRecord()); - List replayResultList = zstdDeserialize( - stringListResultHolder.getReplayResult()); - if (categoryType.isEntryPoint()) { - boolean recordEmpty = CollectionUtils.isEmpty(recordList); - boolean replayResultEmpty = CollectionUtils.isEmpty(replayResultList); + List replayResultList = zstdDeserialize(stringListResultHolder.getReplayResult()); + + if (categoryType.isEntryPoint() && (CollectionUtils.isEmpty(recordList) || CollectionUtils.isEmpty(replayResultList))) { // call missing or new call - if (recordEmpty || replayResultEmpty) { - return Collections.emptyList(); - } + return Collections.emptyList(); } + resultHolder.setRecord(recordList); resultHolder.setReplayResult(replayResultList); + resultHolder.setNeedMatch(true); + } + return decodedListResult; + } + + /** + * Processing of packets that do not require matching + * @param replayResultResponseType + * @return + */ + private List processMatchNotNeeded(QueryReplayResultResponseType replayResultResponseType) { + List replayResults = replayResultResponseType.getReplayResults(); + if (CollectionUtils.isEmpty(replayResults)) { + LOGGER.warn("query replay result has empty size"); + return Collections.emptyList(); + } + + List decodedListResult = new ArrayList<>(replayResults.size()); + for (CompareRelationResult result : replayResults) { + MockCategoryType categoryType = result.getCategoryType(); + if (categoryType == null || (!categoryType.isEntryPoint() && categoryType.isSkipComparison())) { + continue; + } + + if (categoryType.isEntryPoint() && !categoryType.isSkipComparison() && + (StringUtils.isEmpty(result.getRecordMessage()) || StringUtils.isEmpty(result.getReplayMessage()))) { + // The main category is missing + return Collections.emptyList(); + } + + CategoryComparisonHolder resultHolder = new CategoryComparisonHolder(); + resultHolder.setCategoryName(categoryType.getName()); + + CompareItem recordCompareItem = prepareCompareItemBuilder.build(result, true); + CompareItem replayCompareItem = prepareCompareItemBuilder.build(result, false); + + resultHolder.setCompareResultItem(new CompareResultItem(recordCompareItem, replayCompareItem)); + resultHolder.setNeedMatch(false); + decodedListResult.add(resultHolder); } return decodedListResult; } diff --git a/arex-schedule-web-api/src/main/java/com/arextest/schedule/serialization/ZstdJacksonSerializer.java b/arex-schedule-web-api/src/main/java/com/arextest/schedule/serialization/ZstdJacksonSerializer.java index ba362219..026eff42 100644 --- a/arex-schedule-web-api/src/main/java/com/arextest/schedule/serialization/ZstdJacksonSerializer.java +++ b/arex-schedule-web-api/src/main/java/com/arextest/schedule/serialization/ZstdJacksonSerializer.java @@ -5,6 +5,8 @@ import com.arextest.common.serialization.SerializationProviders; import com.arextest.common.utils.SerializationUtils; import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Base64; @@ -25,12 +27,26 @@ public final class ZstdJacksonSerializer { @Resource private ObjectMapper objectMapper; private SerializationProvider serializationProvider; + public static final byte[] EMPTY_BYTE = new byte[]{}; @PostConstruct void initSerializationProvider() { this.serializationProvider = SerializationProviders.jacksonProvider(this.objectMapper); } + public byte[] serialize(T value) { + if (value == null) { + return EMPTY_BYTE; + } + try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { + serializeTo(value, out); + return out.toByteArray(); + } catch (IOException e) { + LOGGER.error("serialize error:{}", e.getMessage(), e); + } + return EMPTY_BYTE; + } + public void serializeTo(T value, OutputStream outputStream) { if (value == null) { return; diff --git a/pom.xml b/pom.xml index f3ad02a7..af24aa84 100644 --- a/pom.xml +++ b/pom.xml @@ -307,7 +307,7 @@ **/model/**, **/mapping/** - 1.2.19 + 1.3.0 0.6.5.2 0.2.3 3.20.1 @@ -320,5 +320,5 @@ https://github.com/arextest/arex-replay-schedule https://github.com/arextest/arex-replay-schedule - 1.2.17 + 1.2.18 \ No newline at end of file