diff --git a/arex-storage-config/pom.xml b/arex-storage-config/pom.xml index 56bfeae4..5eb16992 100644 --- a/arex-storage-config/pom.xml +++ b/arex-storage-config/pom.xml @@ -45,7 +45,7 @@ arex-storage-service com.arextest - 1.0.48 + 1.0.49 diff --git a/arex-storage-model/pom.xml b/arex-storage-model/pom.xml index 3cf86e94..3f457b96 100644 --- a/arex-storage-model/pom.xml +++ b/arex-storage-model/pom.xml @@ -7,7 +7,7 @@ arex-storage-service com.arextest - 1.0.48 + 1.0.49 diff --git a/arex-storage-model/src/main/java/com/arextest/model/replay/QueryReplayResultResponseType.java b/arex-storage-model/src/main/java/com/arextest/model/replay/QueryReplayResultResponseType.java index 496695d0..32f0ece2 100644 --- a/arex-storage-model/src/main/java/com/arextest/model/replay/QueryReplayResultResponseType.java +++ b/arex-storage-model/src/main/java/com/arextest/model/replay/QueryReplayResultResponseType.java @@ -14,4 +14,5 @@ public class QueryReplayResultResponseType implements Response { private ResponseStatusType responseStatusType; private List resultHolderList; + private Boolean invalidResult; } \ No newline at end of file diff --git a/arex-storage-web-api/pom.xml b/arex-storage-web-api/pom.xml index 5d172c3b..7f1c0c97 100644 --- a/arex-storage-web-api/pom.xml +++ b/arex-storage-web-api/pom.xml @@ -123,7 +123,7 @@ arex-storage-service com.arextest - 1.0.48 + 1.0.49 diff --git a/arex-storage-web-api/src/main/java/com/arextest/storage/beans/StorageAutoConfiguration.java b/arex-storage-web-api/src/main/java/com/arextest/storage/beans/StorageAutoConfiguration.java index f2f64f63..935df69c 100644 --- a/arex-storage-web-api/src/main/java/com/arextest/storage/beans/StorageAutoConfiguration.java +++ b/arex-storage-web-api/src/main/java/com/arextest/storage/beans/StorageAutoConfiguration.java @@ -22,6 +22,7 @@ import com.arextest.storage.service.AgentWorkingListener; import com.arextest.storage.service.AgentWorkingService; import com.arextest.storage.service.AutoDiscoveryEntryPointListener; +import com.arextest.storage.service.InvalidReplayCaseService; import com.arextest.storage.service.MockSourceEditionService; import com.arextest.storage.service.PrepareMockResultService; import com.arextest.storage.service.ScheduleReplayingService; @@ -151,8 +152,9 @@ public AgentWorkingService agentWorkingService(MockResultProvider mockResultProv public AgentWorkingMetricService agentWorkingMetricService( AgentWorkingService agentWorkingService, MockSourceEditionService editableService, - List metricListeners) { - return new AgentWorkingMetricService(agentWorkingService, editableService, metricListeners); + List metricListeners, + InvalidReplayCaseService invalidReplayCaseService) { + return new AgentWorkingMetricService(agentWorkingService, editableService, metricListeners, invalidReplayCaseService); } @Bean @@ -166,8 +168,10 @@ public MatchStrategyMetricService matchStrategyMetricService( @ConditionalOnMissingBean(ScheduleReplayQueryController.class) public ScheduleReplayQueryController scheduleReplayQueryController( ScheduleReplayingService scheduleReplayingService, - PrepareMockResultService prepareMockResultService) { - return new ScheduleReplayQueryController(scheduleReplayingService, prepareMockResultService); + PrepareMockResultService prepareMockResultService, + InvalidReplayCaseService invalidReplayCaseService) { + return new ScheduleReplayQueryController(scheduleReplayingService, prepareMockResultService, + invalidReplayCaseService); } @Bean diff --git a/arex-storage-web-api/src/main/java/com/arextest/storage/client/HttpWepServiceApiClient.java b/arex-storage-web-api/src/main/java/com/arextest/storage/client/HttpWebServiceApiClient.java similarity index 99% rename from arex-storage-web-api/src/main/java/com/arextest/storage/client/HttpWepServiceApiClient.java rename to arex-storage-web-api/src/main/java/com/arextest/storage/client/HttpWebServiceApiClient.java index 01536292..f47567b0 100644 --- a/arex-storage-web-api/src/main/java/com/arextest/storage/client/HttpWepServiceApiClient.java +++ b/arex-storage-web-api/src/main/java/com/arextest/storage/client/HttpWebServiceApiClient.java @@ -35,7 +35,7 @@ */ @Component @Slf4j -public final class HttpWepServiceApiClient { +public final class HttpWebServiceApiClient { private final static int TEN_SECONDS_TIMEOUT = 10_000; private RestTemplate restTemplate; diff --git a/arex-storage-web-api/src/main/java/com/arextest/storage/metric/AgentWorkingMetricService.java b/arex-storage-web-api/src/main/java/com/arextest/storage/metric/AgentWorkingMetricService.java index 87372ef7..0fcf18fc 100644 --- a/arex-storage-web-api/src/main/java/com/arextest/storage/metric/AgentWorkingMetricService.java +++ b/arex-storage-web-api/src/main/java/com/arextest/storage/metric/AgentWorkingMetricService.java @@ -12,9 +12,12 @@ import java.util.concurrent.TimeUnit; import javax.validation.constraints.NotNull; +import com.arextest.storage.service.InvalidReplayCaseService; import com.arextest.storage.service.MockSourceEditionService; +import com.arextest.storage.trace.MDCTracer; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; /** * created by xinyuan_wang on 2023/6/7 @@ -31,15 +34,19 @@ public class AgentWorkingMetricService { private static final String REASON = "reason"; private static final String INVALID_CASE_METHOD_NAME = "invalidCase"; + private static final String INVALID_REPLAY_CASE_METHOD_NAME = "invalidReplayCase"; public final List metricListeners; private final AgentWorkingService agentWorkingService; private final MockSourceEditionService editableService; + private final InvalidReplayCaseService invalidReplayCaseService; + public AgentWorkingMetricService(AgentWorkingService agentWorkingService, MockSourceEditionService editableService, - List metricListeners) { + List metricListeners, InvalidReplayCaseService invalidReplayCaseService) { this.agentWorkingService = agentWorkingService; this.editableService = editableService; this.metricListeners = metricListeners; + this.invalidReplayCaseService = invalidReplayCaseService; } private static long nanosToMillis(long duration) { @@ -74,6 +81,12 @@ public byte[] queryMockResult(@NotNull T recordItem, } public void invalidCase(InvalidCaseRequest requestType) { + // replayId is not empty, means this is a replay case + if (StringUtils.isNotEmpty(requestType.getReplayId())) { + invalidReplayCase(requestType); + return; + } + // recordId is not empty, means this is a record case editableService.invalidCase(ProviderNames.DEFAULT, requestType.getRecordId()); if (CollectionUtils.isEmpty(metricListeners)) { return; @@ -99,4 +112,25 @@ private void recordEntryTime(String path, AREXMocker item, long timeMillis) { } } + private void invalidReplayCase(InvalidCaseRequest request) { + // save into redis + String replayId = request.getReplayId(); + MDCTracer.addReplayId(replayId); + invalidReplayCaseService.saveInvalidCase(replayId); + LOGGER.info("[[title=invalidReplayCase]]invalid replayId:{}", replayId); + MDCTracer.clear(); + // metric + if (CollectionUtils.isEmpty(metricListeners)) { + return; + } + Map tags = new HashMap<>(3); + tags.put(CLIENT_APP_ID, request.getAppId()); + tags.put(PATH, INVALID_REPLAY_CASE_METHOD_NAME); + tags.put(REASON, request.getReason()); + + for (MetricListener metricListener : metricListeners) { + metricListener.recordMatchingCount(METRIC_NAME, tags); + } + } + } diff --git a/arex-storage-web-api/src/main/java/com/arextest/storage/model/InvalidCaseRequest.java b/arex-storage-web-api/src/main/java/com/arextest/storage/model/InvalidCaseRequest.java index 48336051..e9a2ae6a 100644 --- a/arex-storage-web-api/src/main/java/com/arextest/storage/model/InvalidCaseRequest.java +++ b/arex-storage-web-api/src/main/java/com/arextest/storage/model/InvalidCaseRequest.java @@ -15,6 +15,11 @@ public class InvalidCaseRequest { * FastReject or QueueOverFlow */ private String reason; + /** + * Replay id + * replay scene must be not null + */ + private String replayId; @Override public String toString() { @@ -22,6 +27,7 @@ public String toString() { "appId='" + appId + '\'' + ", recordId='" + recordId + '\'' + ", reason=" + reason + + ", replayId='" + replayId + '\'' + '}'; } } diff --git a/arex-storage-web-api/src/main/java/com/arextest/storage/service/InvalidReplayCaseService.java b/arex-storage-web-api/src/main/java/com/arextest/storage/service/InvalidReplayCaseService.java new file mode 100644 index 00000000..67d4ddf7 --- /dev/null +++ b/arex-storage-web-api/src/main/java/com/arextest/storage/service/InvalidReplayCaseService.java @@ -0,0 +1,45 @@ +package com.arextest.storage.service; + +import com.arextest.common.cache.CacheProvider; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; + +/** + * listen agent service query storage service if exception mark replay case invalid + * @author: sldu + * @date: 2023/12/6 13:46 + **/ +@Component +@Slf4j +public class InvalidReplayCaseService { + @Resource + private CacheProvider redisCacheProvider; + private static final byte[] INVALID_CASE_KEY = "invalid_case".getBytes(StandardCharsets.UTF_8); + private static final byte[] INVALID_CASE_VALUE = "1".getBytes(StandardCharsets.UTF_8); + private static final long THREE_MINUTES_EXPIRE = 3 * 60L; + + public void saveInvalidCase(String replayId) { + byte[] key = toInvalidCaseKeyBytes(replayId); + redisCacheProvider.put(key, THREE_MINUTES_EXPIRE, INVALID_CASE_VALUE); + } + public boolean isInvalidCase(String replayId) { + byte[] key = toInvalidCaseKeyBytes(replayId); + try { + byte[] bytes = redisCacheProvider.get(key); + if (bytes != null) { + return true; + } + } catch (Exception e) { + LOGGER.error("isInvalidCase error", e); + } + return false; + } + private byte[] toInvalidCaseKeyBytes(String replayId) { + byte[] paramKey = replayId.getBytes(StandardCharsets.UTF_8); + return ByteBuffer.allocate(INVALID_CASE_KEY.length + paramKey.length).put(INVALID_CASE_KEY).put(paramKey).array(); + } +} \ No newline at end of file diff --git a/arex-storage-web-api/src/main/java/com/arextest/storage/service/MockSourceEditionService.java b/arex-storage-web-api/src/main/java/com/arextest/storage/service/MockSourceEditionService.java index 8bea71af..f326518b 100644 --- a/arex-storage-web-api/src/main/java/com/arextest/storage/service/MockSourceEditionService.java +++ b/arex-storage-web-api/src/main/java/com/arextest/storage/service/MockSourceEditionService.java @@ -7,9 +7,11 @@ import com.arextest.storage.repository.RepositoryProviderFactory; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.Set; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; @@ -52,9 +54,12 @@ public boolean removeAll(String providerName, String recordId) { return false; } Set categoryTypes = providerFactory.getCategoryTypes(); + Map removeResults = new HashMap<>(categoryTypes.size()); for (MockCategoryType categoryType : categoryTypes) { - repositoryWriter.removeBy(categoryType, recordId); + long removeResult = repositoryWriter.removeBy(categoryType, recordId); + removeResults.put(categoryType.getName(), removeResult > 0); } + LOGGER.info("remove all record result:{} for recordId:{}", removeResults, recordId); return true; } diff --git a/arex-storage-web-api/src/main/java/com/arextest/storage/service/QueryConfigService.java b/arex-storage-web-api/src/main/java/com/arextest/storage/service/QueryConfigService.java index 47ceff86..14c41297 100644 --- a/arex-storage-web-api/src/main/java/com/arextest/storage/service/QueryConfigService.java +++ b/arex-storage-web-api/src/main/java/com/arextest/storage/service/QueryConfigService.java @@ -6,7 +6,7 @@ import com.arextest.config.model.vo.QueryConfigOfCategoryResponse; import com.arextest.model.mock.Mocker; import com.arextest.storage.cache.CacheKeyUtils; -import com.arextest.storage.client.HttpWepServiceApiClient; +import com.arextest.storage.client.HttpWebServiceApiClient; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @@ -28,7 +28,7 @@ public class QueryConfigService { @Value("${arex.query.config.cache.expired.seconds:600}") private long cacheExpiredSeconds; @Resource - private HttpWepServiceApiClient httpWepServiceApiClient; + private HttpWebServiceApiClient httpWebServiceApiClient; @Resource private CacheProvider redisCacheProvider; @@ -52,7 +52,7 @@ public QueryConfigOfCategory queryConfigOfCategory(Mocker mocker) { queryConfigOfCategoryRequest.setEntryPoint(mocker.getCategoryType().isEntryPoint()); queryConfigOfCategoryRequest.setOperationName(operationName); QueryConfigOfCategoryResponse queryConfigOfCategoryResponse = - httpWepServiceApiClient.jsonPost(queryConfigOfCategoryUrl, queryConfigOfCategoryRequest, QueryConfigOfCategoryResponse.class); + httpWebServiceApiClient.jsonPost(queryConfigOfCategoryUrl, queryConfigOfCategoryRequest, QueryConfigOfCategoryResponse.class); if (queryConfigOfCategoryResponse != null && queryConfigOfCategoryResponse.getBody() != null) { putConfigCache(appId, categoryName, operationName, queryConfigOfCategoryResponse.getBody()); return queryConfigOfCategoryResponse.getBody(); diff --git a/arex-storage-web-api/src/main/java/com/arextest/storage/web/controller/AgentRecordingController.java b/arex-storage-web-api/src/main/java/com/arextest/storage/web/controller/AgentRecordingController.java index 599e9652..82d867f5 100644 --- a/arex-storage-web-api/src/main/java/com/arextest/storage/web/controller/AgentRecordingController.java +++ b/arex-storage-web-api/src/main/java/com/arextest/storage/web/controller/AgentRecordingController.java @@ -145,10 +145,11 @@ public Response saveTest( @ResponseBody public Response invalidCase(@RequestBody InvalidCaseRequest requestType) { if (StringUtils.isEmpty(requestType.getRecordId())) { - LOGGER.warn("agent invalid case recordId empty, {}", requestType); + LOGGER.warn("[[title=invalidCase]]agent invalid case recordId empty, {}", requestType); return ResponseUtils.emptyRecordIdResponse(); } - LOGGER.info("agent invalid case, request:{}", requestType); + MDCTracer.addRecordId(requestType.getRecordId()); + LOGGER.info("[[title=invalidCase]]agent invalid case, request:{}", requestType); CompletableFuture.runAsync(() -> agentWorkingMetricService.invalidCase(requestType)); return ResponseUtils.successResponse(true); } diff --git a/arex-storage-web-api/src/main/java/com/arextest/storage/web/controller/ScheduleReplayQueryController.java b/arex-storage-web-api/src/main/java/com/arextest/storage/web/controller/ScheduleReplayQueryController.java index 72ec1c6e..2a024f18 100644 --- a/arex-storage-web-api/src/main/java/com/arextest/storage/web/controller/ScheduleReplayQueryController.java +++ b/arex-storage-web-api/src/main/java/com/arextest/storage/web/controller/ScheduleReplayQueryController.java @@ -17,6 +17,7 @@ import com.arextest.model.response.Response; import com.arextest.storage.mock.MockerPostProcessor; import com.arextest.storage.repository.ProviderNames; +import com.arextest.storage.service.InvalidReplayCaseService; import com.arextest.storage.service.PrepareMockResultService; import com.arextest.storage.service.ScheduleReplayingService; import com.arextest.storage.trace.MDCTracer; @@ -53,6 +54,8 @@ public class ScheduleReplayQueryController { private final PrepareMockResultService prepareMockResultService; + private final InvalidReplayCaseService invalidReplayCaseService; + /** * fetch the replay result for compare * @@ -81,6 +84,7 @@ public Response replayResult(@RequestBody QueryReplayResultRequestType requestTy scheduleReplayingService.queryReplayResult(recordId, replayResultId); QueryReplayResultResponseType responseType = new QueryReplayResultResponseType(); responseType.setResultHolderList(resultHolderList); + responseType.setInvalidResult(invalidReplayCaseService.isInvalidCase(replayResultId)); return ResponseUtils.successResponse(responseType); } catch (Throwable throwable) { LOGGER.error("replayResult error:{} ,recordId:{} ,replayResultId:{}", diff --git a/pom.xml b/pom.xml index ce0e6d22..a89f88c8 100644 --- a/pom.xml +++ b/pom.xml @@ -408,5 +408,5 @@ https://github.com/arextest/arex-storage - 1.0.48 + 1.0.49 \ No newline at end of file