From a13fa989253d76fd67536f0ff872a4586105f779 Mon Sep 17 00:00:00 2001 From: pangdayuan Date: Wed, 12 Jun 2024 16:01:30 +0800 Subject: [PATCH] feat: Compatible with replayResult interface logic --- arex-schedule-web-api/pom.xml | 4 +- .../client/HttpWepServiceApiClient.java | 21 +++- .../client/ZstdJacksonMessageConverter.java | 4 +- .../arextest/schedule/common/JsonUtils.java | 11 +- .../comparer/CategoryComparisonHolder.java | 13 +++ .../comparer/CompareItemConvertFactory.java | 22 ++++ .../comparer/CompareItemConverter.java | 14 +++ .../DatabaseCompareItemConverterImpl.java | 91 +++++++++++++++ .../RedisCompareItemConverterImpl.java | 54 +++++++++ .../impl/DefaultReplayResultComparer.java | 32 +++++- .../impl/PrepareCompareItemBuilder.java | 77 +++++-------- .../PrepareCompareSourceRemoteLoader.java | 104 +++++++++++++----- .../serialization/ZstdJacksonSerializer.java | 16 +++ pom.xml | 4 +- 14 files changed, 382 insertions(+), 85 deletions(-) create mode 100644 arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/CompareItemConvertFactory.java create mode 100644 arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/CompareItemConverter.java create mode 100644 arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/converter/DatabaseCompareItemConverterImpl.java create mode 100644 arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/converter/RedisCompareItemConverterImpl.java 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..2dde101f 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,18 @@ 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/CompareItemConvertFactory.java b/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/CompareItemConvertFactory.java new file mode 100644 index 00000000..bf4512d5 --- /dev/null +++ b/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/CompareItemConvertFactory.java @@ -0,0 +1,22 @@ +package com.arextest.schedule.comparer; + +import com.arextest.model.mock.MockCategoryType; +import java.util.function.Function; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class CompareItemConvertFactory { + private final Map categoryConverters; + public CompareItemConvertFactory(@Autowired List converters) { + this.categoryConverters = converters.stream().filter(c -> c.getCategoryType() != null) + .collect(Collectors.toMap(CompareItemConverter::getCategoryType, Function.identity())); + } + + public CompareItemConverter getConverts(MockCategoryType categoryType) { + return categoryConverters.getOrDefault(categoryType, null); + } +} diff --git a/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/CompareItemConverter.java b/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/CompareItemConverter.java new file mode 100644 index 00000000..4abca665 --- /dev/null +++ b/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/CompareItemConverter.java @@ -0,0 +1,14 @@ +package com.arextest.schedule.comparer; + +import com.arextest.model.mock.AREXMocker; +import com.arextest.model.mock.MockCategoryType; +import com.arextest.model.replay.CompareRelationResult; + +public interface CompareItemConverter { + MockCategoryType getCategoryType(); + + CompareItem convert(AREXMocker mocker); + + CompareItem convert(CompareRelationResult relationResult, boolean recordCompareItem); + +} diff --git a/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/converter/DatabaseCompareItemConverterImpl.java b/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/converter/DatabaseCompareItemConverterImpl.java new file mode 100644 index 00000000..186a2ea0 --- /dev/null +++ b/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/converter/DatabaseCompareItemConverterImpl.java @@ -0,0 +1,91 @@ +package com.arextest.schedule.comparer.converter; + +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.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 MockCategoryType getCategoryType() { + return MockCategoryType.DATABASE; + } + + @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/RedisCompareItemConverterImpl.java b/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/converter/RedisCompareItemConverterImpl.java new file mode 100644 index 00000000..2f228ec8 --- /dev/null +++ b/arex-schedule-web-api/src/main/java/com/arextest/schedule/comparer/converter/RedisCompareItemConverterImpl.java @@ -0,0 +1,54 @@ +package com.arextest.schedule.comparer.converter; + +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.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 MockCategoryType getCategoryType() { + return MockCategoryType.REDIS; + } + + @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..d2be1a8e 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,13 @@ 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 com.arextest.schedule.comparer.CompareItemConvertFactory; +import com.arextest.schedule.comparer.CompareItemConverter; import java.util.Objects; -import org.apache.commons.lang3.StringUtils; +import javax.annotation.Resource; import org.springframework.stereotype.Component; /** @@ -18,14 +15,19 @@ * @since 2021/11/23 */ @Component -final class PrepareCompareItemBuilder { +public class PrepareCompareItemBuilder { + + @Resource + private CompareItemConvertFactory factory; CompareItem build(AREXMocker instance) { - MockCategoryType categoryType = instance.getCategoryType(); - String operationKey = operationName(categoryType, instance.getTargetRequest(), instance.getOperationName()); - if (StringUtils.isEmpty(operationKey)) { - operationKey = instance.getOperationName(); + CompareItemConverter converter = factory.getConverts(instance.getCategoryType()); + if (converter != null) { + return converter.convert(instance); } + + MockCategoryType categoryType = instance.getCategoryType(); + String operationKey = instance.getOperationName(); long createTime = instance.getCreationTime(); String body; String compareKey = instance.getId(); @@ -35,8 +37,6 @@ CompareItem build(AREXMocker instance) { : 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(); @@ -44,41 +44,15 @@ CompareItem build(AREXMocker instance) { return new CompareItemImpl(operationKey, body, compareKey, createTime, entryPointCategory); } - 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); + public CompareItem build(CompareRelationResult result, boolean recordCompareItem) { + CompareItemConverter converter = factory.getConverts(result.getCategoryType()); + if (converter != null) { + return converter.convert(result, recordCompareItem); } - if (Objects.equals(categoryType, MockCategoryType.REDIS)) { - return target.attributeAsString(MockAttributeNames.CLUSTER_NAME); - } - return operationName; + return new CompareItemImpl(result, recordCompareItem); } - 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 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 +60,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