This is an automated email from the ASF dual-hosted git repository. liubao pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git
commit da7b7718f493600670076b8418dbb043977ffed4 Author: liubao <[email protected]> AuthorDate: Wed Dec 30 17:45:45 2020 +0800 [SCB-2116]improve algorithm to match when applying rules --- .../servicecomb/governance/InvocationContext.java} | 15 +--- .../servicecomb/governance/MatchersManager.java | 57 ++++++++++--- .../governance/marker/GovHttpRequest.java | 20 +++++ .../governance/marker/TrafficMarker.java | 31 +++++++ .../governance/policy/AbstractPolicy.java | 24 ++++-- .../policy/{GovRule.java => GovernanceRule.java} | 42 +++++++++- .../governance/properties/BulkheadProperties.java | 2 +- .../properties/CircuitBreakerProperties.java | 2 +- ...ovProperties.java => GovernanceProperties.java} | 19 +++-- .../governance/properties/MatchProperties.java | 7 +- .../PolicyProperties.java} | 25 ++---- .../governance/properties/RateLimitProperties.java | 2 +- .../governance/properties/RetryProperties.java | 2 +- .../governance/service/MatchersService.java | 5 +- .../MatchersServiceImpl.java} | 46 ++++++----- .../governance/service/PolicyServiceImpl.java | 6 +- .../servicecomb/governance/FlowControlTest.java | 94 ++++++++++++++++++++++ ...tiesTest.java => GovernancePropertiesTest.java} | 8 +- ...hersService.java => MockInvocationContext.java} | 29 +++++-- 19 files changed, 335 insertions(+), 101 deletions(-) diff --git a/governance/src/test/java/org/apache/servicecomb/governance/MockMatchersService.java b/governance/src/main/java/org/apache/servicecomb/governance/InvocationContext.java similarity index 69% copy from governance/src/test/java/org/apache/servicecomb/governance/MockMatchersService.java copy to governance/src/main/java/org/apache/servicecomb/governance/InvocationContext.java index 1387312..07d03ce 100644 --- a/governance/src/test/java/org/apache/servicecomb/governance/MockMatchersService.java +++ b/governance/src/main/java/org/apache/servicecomb/governance/InvocationContext.java @@ -17,17 +17,10 @@ package org.apache.servicecomb.governance; -import java.util.List; +import java.util.Map; -import org.springframework.stereotype.Component; +public interface InvocationContext { + Map<String, Boolean> getCalculatedMatches(); -import org.apache.servicecomb.governance.marker.GovHttpRequest; -import org.apache.servicecomb.governance.service.MatchersService; - -@Component -public class MockMatchersService implements MatchersService { - @Override - public List<String> getMatchedNames(GovHttpRequest govHttpRequest) { - return null; - } + void addMatch(String key, Boolean value); } diff --git a/governance/src/main/java/org/apache/servicecomb/governance/MatchersManager.java b/governance/src/main/java/org/apache/servicecomb/governance/MatchersManager.java index c35c1a1..6a7ec0e 100644 --- a/governance/src/main/java/org/apache/servicecomb/governance/MatchersManager.java +++ b/governance/src/main/java/org/apache/servicecomb/governance/MatchersManager.java @@ -16,17 +16,18 @@ */ package org.apache.servicecomb.governance; +import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Map.Entry; -import org.apache.servicecomb.governance.policy.Policy; +import org.apache.servicecomb.governance.marker.GovHttpRequest; +import org.apache.servicecomb.governance.policy.AbstractPolicy; import org.apache.servicecomb.governance.service.MatchersService; import org.apache.servicecomb.governance.service.PolicyService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import org.apache.servicecomb.governance.marker.GovHttpRequest; - @Component public class MatchersManager { @@ -36,17 +37,49 @@ public class MatchersManager { @Autowired private PolicyService policyService; + @Autowired + private InvocationContext invocationContext; + public MatchersManager() { } - public Map<String, Policy> match(GovHttpRequest request) { - /** - * 1.获取该请求携带的marker - */ - List<String> marks = matchersService.getMatchedNames(request); - /** - * 2.通过 marker获取到所有的policy - */ - return policyService.getAllPolicies(marks); + public <T extends AbstractPolicy> T match(GovHttpRequest request, Map<String, T> policies) { + List<T> matchedPolicy = new ArrayList<>(); + List<String> matchedKeys = new ArrayList<>(); + + Map<String, Boolean> calculatedMatches = invocationContext.getCalculatedMatches(); + calculatedMatches.forEach((k, v) -> { + if (v) { + matchedKeys.add(k); + } + }); + + for (Entry<String, T> entry : policies.entrySet()) { + T policy = entry.getValue(); + + if (policy.match(matchedKeys)) { + matchedPolicy.add(policy); + continue; + } + + List<String> parsedMatches = policy.getParsedMatch(); + if (parsedMatches != null) { + parsedMatches.stream().forEach(key -> { + if (!calculatedMatches.containsKey(key)) { + boolean keyMatch = matchersService.checkMatch(request, key); + invocationContext.addMatch(key, keyMatch); + if (keyMatch) { + matchedPolicy.add(policy); + } + } + }); + } + } + + if (matchedPolicy.size() > 0) { + matchedPolicy.sort(AbstractPolicy::compare); + return matchedPolicy.get(0); + } + return null; } } diff --git a/governance/src/main/java/org/apache/servicecomb/governance/marker/GovHttpRequest.java b/governance/src/main/java/org/apache/servicecomb/governance/marker/GovHttpRequest.java index bc4d9ea..2176ef5 100644 --- a/governance/src/main/java/org/apache/servicecomb/governance/marker/GovHttpRequest.java +++ b/governance/src/main/java/org/apache/servicecomb/governance/marker/GovHttpRequest.java @@ -18,7 +18,12 @@ package org.apache.servicecomb.governance.marker; import java.util.Map; +import org.springframework.util.Assert; + public class GovHttpRequest { + private final String serviceName; + + private final String version; private Map<String, String> headers; @@ -26,6 +31,21 @@ public class GovHttpRequest { private String method; + public GovHttpRequest(String serviceName, String version) { + Assert.notNull(serviceName, "serviceName should not be null"); + Assert.notNull(version, "version should not be null"); + this.serviceName = serviceName; + this.version = version; + } + + public String getServiceName() { + return serviceName; + } + + public String getVersion() { + return version; + } + public Map<String, String> getHeaders() { return headers; } diff --git a/governance/src/main/java/org/apache/servicecomb/governance/marker/TrafficMarker.java b/governance/src/main/java/org/apache/servicecomb/governance/marker/TrafficMarker.java index ba4cbf7..b64c168 100644 --- a/governance/src/main/java/org/apache/servicecomb/governance/marker/TrafficMarker.java +++ b/governance/src/main/java/org/apache/servicecomb/governance/marker/TrafficMarker.java @@ -16,8 +16,11 @@ */ package org.apache.servicecomb.governance.marker; +import java.util.Arrays; import java.util.List; +import org.apache.commons.lang3.StringUtils; + public class TrafficMarker { private String services; @@ -39,4 +42,32 @@ public class TrafficMarker { public void setMatches(List<Matcher> matches) { this.matches = matches; } + + public boolean checkMatch(GovHttpRequest govHttpRequest, RequestProcessor requestProcessor, String name) { + if (!servicesMatch(govHttpRequest)) { + return false; + } + + return this.matches.stream().anyMatch(match -> + match.getName().equals(name) && requestProcessor.match(govHttpRequest, match)); + } + + + private boolean servicesMatch(GovHttpRequest govHttpRequest) { + if (StringUtils.isEmpty(services)) { + return true; + } + + return Arrays.stream(services.split(",")).anyMatch(ser -> { + String[] serviceAndVersion = ser.split(":"); + if (serviceAndVersion.length == 1) { + return govHttpRequest.getServiceName().equals(serviceAndVersion[0]); + } else if (serviceAndVersion.length == 2) { + return govHttpRequest.getServiceName().equals(serviceAndVersion[0]) && govHttpRequest.getVersion() + .equals(serviceAndVersion[1]); + } else { + return false; + } + }); + } } diff --git a/governance/src/main/java/org/apache/servicecomb/governance/policy/AbstractPolicy.java b/governance/src/main/java/org/apache/servicecomb/governance/policy/AbstractPolicy.java index ae47da3..3e496c4 100644 --- a/governance/src/main/java/org/apache/servicecomb/governance/policy/AbstractPolicy.java +++ b/governance/src/main/java/org/apache/servicecomb/governance/policy/AbstractPolicy.java @@ -16,20 +16,19 @@ */ package org.apache.servicecomb.governance.policy; -import java.util.Arrays; import java.util.List; public abstract class AbstractPolicy implements Policy { private String name; - private GovRule rules; + private GovernanceRule rules; - public GovRule getRules() { + public GovernanceRule getRules() { return rules; } - public void setRules(GovRule rules) { + public void setRules(GovernanceRule rules) { this.rules = rules; } @@ -39,13 +38,24 @@ public abstract class AbstractPolicy implements Policy { @Override public boolean match(List<String> items) { - if (rules == null || rules.getMatch() == null) { + if (rules == null) { return false; } + return items.stream().anyMatch(item -> rules.match(item)); + } + + public static int compare(AbstractPolicy policy1, AbstractPolicy policy2) { + int p1 = policy1.rules == null ? 0 : policy1.rules.getPrecedence(); + int p2 = policy2.rules == null ? 0 : policy2.rules.getPrecedence(); + return p1 - p2; + } - List<String> configuredItems = Arrays.asList(rules.getMatch().split(",")); + public List<String> getParsedMatch() { + if (rules == null) { + return null; + } - return items.stream().anyMatch(item -> configuredItems.contains(item)); + return rules.getParsedMatch(); } @Override diff --git a/governance/src/main/java/org/apache/servicecomb/governance/policy/GovRule.java b/governance/src/main/java/org/apache/servicecomb/governance/policy/GovernanceRule.java similarity index 57% copy from governance/src/main/java/org/apache/servicecomb/governance/policy/GovRule.java copy to governance/src/main/java/org/apache/servicecomb/governance/policy/GovernanceRule.java index 58db001..d75b250 100644 --- a/governance/src/main/java/org/apache/servicecomb/governance/policy/GovRule.java +++ b/governance/src/main/java/org/apache/servicecomb/governance/policy/GovernanceRule.java @@ -17,10 +17,18 @@ package org.apache.servicecomb.governance.policy; -public class GovRule { +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; + +public class GovernanceRule { + private static final String MATCH_NONE = "none"; private String match; + private List<String> parsedMatch; + private int precedence; public String getMatch() { @@ -38,4 +46,36 @@ public class GovRule { public void setPrecedence(int precedence) { this.precedence = precedence; } + + public boolean match(String name) { + if (StringUtils.isEmpty(this.match)) { + return false; + } + + if (MATCH_NONE.equals(this.match)) { + return true; + } + + if (this.parsedMatch == null) { + this.parsedMatch = Arrays.asList(this.match.split(",")); + } + + return parsedMatch.contains(name); + } + + public List<String> getParsedMatch() { + if (StringUtils.isEmpty(this.match)) { + return null; + } + + if (MATCH_NONE.equals(this.match)) { + return null; + } + + if (this.parsedMatch == null) { + this.parsedMatch = Arrays.asList(this.match.split(",")); + } + + return parsedMatch; + } } diff --git a/governance/src/main/java/org/apache/servicecomb/governance/properties/BulkheadProperties.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/BulkheadProperties.java index b61f4d3..2e340b7 100644 --- a/governance/src/main/java/org/apache/servicecomb/governance/properties/BulkheadProperties.java +++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/BulkheadProperties.java @@ -21,7 +21,7 @@ import org.apache.servicecomb.governance.policy.BulkheadPolicy; import org.springframework.stereotype.Component; @Component -public class BulkheadProperties extends GovProperties<BulkheadPolicy> { +public class BulkheadProperties extends PolicyProperties<BulkheadPolicy> { public static final String MATCH_BULKHEAD__KEY = "servicecomb.bulkhead"; public BulkheadProperties() { diff --git a/governance/src/main/java/org/apache/servicecomb/governance/properties/CircuitBreakerProperties.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/CircuitBreakerProperties.java index 5465f66..578d346 100644 --- a/governance/src/main/java/org/apache/servicecomb/governance/properties/CircuitBreakerProperties.java +++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/CircuitBreakerProperties.java @@ -20,7 +20,7 @@ import org.apache.servicecomb.governance.policy.CircuitBreakerPolicy; import org.springframework.stereotype.Component; @Component -public class CircuitBreakerProperties extends GovProperties<CircuitBreakerPolicy> { +public class CircuitBreakerProperties extends PolicyProperties<CircuitBreakerPolicy> { public static final String MATCH_CIRCUITBREAKER_KEY = "servicecomb.circuitBreaker"; public CircuitBreakerProperties() { diff --git a/governance/src/main/java/org/apache/servicecomb/governance/properties/GovProperties.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/GovernanceProperties.java similarity index 91% rename from governance/src/main/java/org/apache/servicecomb/governance/properties/GovProperties.java rename to governance/src/main/java/org/apache/servicecomb/governance/properties/GovernanceProperties.java index 3a498e6..ab852eb 100644 --- a/governance/src/main/java/org/apache/servicecomb/governance/properties/GovProperties.java +++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/GovernanceProperties.java @@ -41,11 +41,12 @@ import org.yaml.snakeyaml.error.YAMLException; import org.yaml.snakeyaml.representer.Representer; import com.google.common.eventbus.Subscribe; + import org.apache.servicecomb.governance.event.ConfigurationChangedEvent; import org.apache.servicecomb.governance.event.EventManager; -public abstract class GovProperties<T> implements InitializingBean { - private static final Logger LOGGER = LoggerFactory.getLogger(GovProperties.class); +public abstract class GovernanceProperties<T> implements InitializingBean { + private static final Logger LOGGER = LoggerFactory.getLogger(GovernanceProperties.class); private final Representer representer = new Representer(); @@ -58,7 +59,7 @@ public abstract class GovProperties<T> implements InitializingBean { protected Class<T> entityClass; - protected GovProperties(String key) { + protected GovernanceProperties(String key) { configKey = key; representer.getPropertyUtils().setSkipMissingProperties(true); EventManager.register(this); @@ -75,7 +76,7 @@ public abstract class GovProperties<T> implements InitializingBean { for (String key : event.getChangedConfigurations()) { if (key.startsWith(configKey + ".")) { // 删除的情况, 从配置文件读取配置。 需要保证 environment 已经刷新配置值。 - T entityItem = parseEntityItem(environment.getProperty(key)); + T entityItem = parseEntityItem(key, environment.getProperty(key)); String mapKey = key.substring((configKey + ".").length()); if (entityItem == null) { parsedEntity.remove(mapKey); @@ -142,7 +143,7 @@ public abstract class GovProperties<T> implements InitializingBean { Map<String, T> resultMap = new HashMap<>(); for (Entry<String, String> entry : yamlEntity.entrySet()) { - T marker = parseEntityItem(entry.getValue()); + T marker = parseEntityItem(entry.getKey(), entry.getValue()); if (marker != null) { resultMap.put(entry.getKey(), marker); } @@ -152,14 +153,18 @@ public abstract class GovProperties<T> implements InitializingBean { protected abstract Class<T> getEntityClass(); - protected T parseEntityItem(String value) { + protected abstract void setName(T value, String key); + + protected T parseEntityItem(String key, String value) { if (StringUtils.isEmpty(value)) { return null; } try { Yaml entityParser = new Yaml(new Constructor(new TypeDescription(entityClass, entityClass)), representer); - return entityParser.loadAs(value, entityClass); + T result = entityParser.loadAs(value, entityClass); + setName(result, key); + return result; } catch (YAMLException e) { LOGGER.error("governance config yaml is illegal : {}", e.getMessage()); } diff --git a/governance/src/main/java/org/apache/servicecomb/governance/properties/MatchProperties.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/MatchProperties.java index c910518..7a2a5ae 100644 --- a/governance/src/main/java/org/apache/servicecomb/governance/properties/MatchProperties.java +++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/MatchProperties.java @@ -20,7 +20,7 @@ import org.apache.servicecomb.governance.marker.TrafficMarker; import org.springframework.stereotype.Component; @Component -public class MatchProperties extends GovProperties<TrafficMarker> { +public class MatchProperties extends GovernanceProperties<TrafficMarker> { public static final String MATCH_POLICY_KEY = "servicecomb.matchGroup"; public MatchProperties() { @@ -31,4 +31,9 @@ public class MatchProperties extends GovProperties<TrafficMarker> { public Class<TrafficMarker> getEntityClass() { return TrafficMarker.class; } + + @Override + protected void setName(TrafficMarker value, String key) { + // do nothing + } } diff --git a/governance/src/main/java/org/apache/servicecomb/governance/policy/GovRule.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/PolicyProperties.java similarity index 68% rename from governance/src/main/java/org/apache/servicecomb/governance/policy/GovRule.java rename to governance/src/main/java/org/apache/servicecomb/governance/properties/PolicyProperties.java index 58db001..73a3a07 100644 --- a/governance/src/main/java/org/apache/servicecomb/governance/policy/GovRule.java +++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/PolicyProperties.java @@ -15,27 +15,16 @@ * limitations under the License. */ -package org.apache.servicecomb.governance.policy; +package org.apache.servicecomb.governance.properties; -public class GovRule { +import org.apache.servicecomb.governance.policy.AbstractPolicy; - private String match; - - private int precedence; - - public String getMatch() { - return match; - } - - public void setMatch(String match) { - this.match = match; - } - - public int getPrecedence() { - return precedence; +public abstract class PolicyProperties<T extends AbstractPolicy> extends GovernanceProperties<T> { + protected PolicyProperties(String key) { + super(key); } - public void setPrecedence(int precedence) { - this.precedence = precedence; + protected void setName(T value, String key) { + value.setName(key); } } diff --git a/governance/src/main/java/org/apache/servicecomb/governance/properties/RateLimitProperties.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/RateLimitProperties.java index e1a2653..472901c 100644 --- a/governance/src/main/java/org/apache/servicecomb/governance/properties/RateLimitProperties.java +++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/RateLimitProperties.java @@ -21,7 +21,7 @@ import org.apache.servicecomb.governance.policy.RateLimitingPolicy; import org.springframework.stereotype.Component; @Component -public class RateLimitProperties extends GovProperties<RateLimitingPolicy> { +public class RateLimitProperties extends PolicyProperties<RateLimitingPolicy> { public static final String MATCH_RATE_LIMIT_KEY = "servicecomb.rateLimiting"; public RateLimitProperties() { diff --git a/governance/src/main/java/org/apache/servicecomb/governance/properties/RetryProperties.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/RetryProperties.java index 9c87ba2..483ea52 100644 --- a/governance/src/main/java/org/apache/servicecomb/governance/properties/RetryProperties.java +++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/RetryProperties.java @@ -20,7 +20,7 @@ import org.apache.servicecomb.governance.policy.RetryPolicy; import org.springframework.stereotype.Component; @Component -public class RetryProperties extends GovProperties<RetryPolicy> { +public class RetryProperties extends PolicyProperties<RetryPolicy> { public static final String MATCH_RETRY_KEY = "servicecomb.retry"; public RetryProperties() { diff --git a/governance/src/main/java/org/apache/servicecomb/governance/service/MatchersService.java b/governance/src/main/java/org/apache/servicecomb/governance/service/MatchersService.java index 265e632..bb01422 100644 --- a/governance/src/main/java/org/apache/servicecomb/governance/service/MatchersService.java +++ b/governance/src/main/java/org/apache/servicecomb/governance/service/MatchersService.java @@ -18,9 +18,6 @@ package org.apache.servicecomb.governance.service; import org.apache.servicecomb.governance.marker.GovHttpRequest; -import java.util.List; - public interface MatchersService { - - List<String> getMatchedNames(GovHttpRequest govHttpRequest); + boolean checkMatch(GovHttpRequest govHttpRequest, String key); } diff --git a/governance/src/main/java/org/apache/servicecomb/governance/MatchersManager.java b/governance/src/main/java/org/apache/servicecomb/governance/service/MatchersServiceImpl.java similarity index 54% copy from governance/src/main/java/org/apache/servicecomb/governance/MatchersManager.java copy to governance/src/main/java/org/apache/servicecomb/governance/service/MatchersServiceImpl.java index c35c1a1..0df3159 100644 --- a/governance/src/main/java/org/apache/servicecomb/governance/MatchersManager.java +++ b/governance/src/main/java/org/apache/servicecomb/governance/service/MatchersServiceImpl.java @@ -14,39 +14,41 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.servicecomb.governance; -import java.util.List; +package org.apache.servicecomb.governance.service; + import java.util.Map; -import org.apache.servicecomb.governance.policy.Policy; -import org.apache.servicecomb.governance.service.MatchersService; -import org.apache.servicecomb.governance.service.PolicyService; +import org.apache.servicecomb.governance.marker.GovHttpRequest; +import org.apache.servicecomb.governance.marker.RequestProcessor; +import org.apache.servicecomb.governance.marker.TrafficMarker; +import org.apache.servicecomb.governance.properties.MatchProperties; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import org.apache.servicecomb.governance.marker.GovHttpRequest; - @Component -public class MatchersManager { - +public class MatchersServiceImpl implements MatchersService { @Autowired - private MatchersService matchersService; + private RequestProcessor requestProcessor; @Autowired - private PolicyService policyService; + private MatchProperties matchProperties; - public MatchersManager() { - } + @Override + public boolean checkMatch(GovHttpRequest govHttpRequest, String key) { + Map<String, TrafficMarker> parsedEntity = matchProperties.getParsedEntity(); + + String[] subKeys = key.split("\\."); + if (subKeys.length != 2) { + return false; + } + + TrafficMarker trafficMarker = parsedEntity.get(subKeys[0]); + + if (trafficMarker == null) { + return false; + } - public Map<String, Policy> match(GovHttpRequest request) { - /** - * 1.获取该请求携带的marker - */ - List<String> marks = matchersService.getMatchedNames(request); - /** - * 2.通过 marker获取到所有的policy - */ - return policyService.getAllPolicies(marks); + return trafficMarker.checkMatch(govHttpRequest, requestProcessor, subKeys[1]); } } diff --git a/governance/src/main/java/org/apache/servicecomb/governance/service/PolicyServiceImpl.java b/governance/src/main/java/org/apache/servicecomb/governance/service/PolicyServiceImpl.java index 03f1a1b..47fa0d6 100644 --- a/governance/src/main/java/org/apache/servicecomb/governance/service/PolicyServiceImpl.java +++ b/governance/src/main/java/org/apache/servicecomb/governance/service/PolicyServiceImpl.java @@ -29,7 +29,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; -import org.apache.servicecomb.governance.properties.GovProperties; +import org.apache.servicecomb.governance.properties.GovernanceProperties; @Component public class PolicyServiceImpl implements PolicyService { @@ -37,7 +37,7 @@ public class PolicyServiceImpl implements PolicyService { private static final String MATCH_NONE = "none"; @Autowired - private List<GovProperties<? extends AbstractPolicy>> propertiesList; + private List<GovernanceProperties<? extends AbstractPolicy>> propertiesList; @Override public Map<String, Policy> getAllPolicies(List<String> marks) { @@ -47,7 +47,7 @@ public class PolicyServiceImpl implements PolicyService { return policies; } - for (GovProperties<? extends AbstractPolicy> properties : propertiesList) { + for (GovernanceProperties<? extends AbstractPolicy> properties : propertiesList) { Policy policy = match(properties.getParsedEntity(), marks); if (policy != null) { policies.put(properties.getClass().getName(), policy); diff --git a/governance/src/test/java/org/apache/servicecomb/governance/FlowControlTest.java b/governance/src/test/java/org/apache/servicecomb/governance/FlowControlTest.java new file mode 100644 index 0000000..8aeddba --- /dev/null +++ b/governance/src/test/java/org/apache/servicecomb/governance/FlowControlTest.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.governance; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.servicecomb.governance.handler.RateLimitingHandler; +import org.apache.servicecomb.governance.marker.GovHttpRequest; +import org.apache.servicecomb.governance.policy.Policy; +import org.apache.servicecomb.governance.properties.RateLimitProperties; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.ConfigFileApplicationContextInitializer; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +import io.github.resilience4j.decorators.Decorators; +import io.github.resilience4j.decorators.Decorators.DecorateCheckedSupplier; +import io.github.resilience4j.ratelimiter.RequestNotPermitted; + +@RunWith(SpringRunner.class) +@ContextConfiguration(locations = "classpath:META-INF/spring/*.xml", initializers = ConfigFileApplicationContextInitializer.class) +public class FlowControlTest { + @Autowired + private RateLimitingHandler rateLimitingHandler; + + @Autowired + private RateLimitProperties rateLimitProperties; + + @Autowired + private MatchersManager matchersManager; + + @Test + public void test_rate_limiting_work() throws Throwable { + DecorateCheckedSupplier<Object> ds = Decorators.ofCheckedSupplier(() -> { + return "test"; + }); + + GovHttpRequest request = new GovHttpRequest("testService", "1.0"); + request.setUri("/hello"); + Policy policy = matchersManager.match(request, rateLimitProperties.getParsedEntity()); + Assert.assertNotNull(policy); + DecorateCheckedSupplier<Object> dcs = rateLimitingHandler.process(ds, policy); + + Assert.assertEquals("test", dcs.get()); + + // flow control + CountDownLatch cd = new CountDownLatch(10); + AtomicBoolean expected = new AtomicBoolean(false); + AtomicBoolean notExpected = new AtomicBoolean(false); + for (int i = 0; i < 10; i++) { + new Thread() { + public void run() { + try { + DecorateCheckedSupplier<Object> dcs = rateLimitingHandler.process(ds, policy); + Object result = dcs.get(); + if (!"test".equals(result)) { + notExpected.set(true); + } + } catch (Throwable e) { + if (e instanceof RequestNotPermitted) { + expected.set(true); + } else { + notExpected.set(true); + } + } + cd.countDown(); + } + }.start(); + } + cd.await(1, TimeUnit.SECONDS); + Assert.assertTrue(expected.get()); + Assert.assertFalse(notExpected.get()); + } +} diff --git a/governance/src/test/java/org/apache/servicecomb/governance/GovPropertiesTest.java b/governance/src/test/java/org/apache/servicecomb/governance/GovernancePropertiesTest.java similarity index 97% rename from governance/src/test/java/org/apache/servicecomb/governance/GovPropertiesTest.java rename to governance/src/test/java/org/apache/servicecomb/governance/GovernancePropertiesTest.java index 9b4d3c9..560bf05 100644 --- a/governance/src/test/java/org/apache/servicecomb/governance/GovPropertiesTest.java +++ b/governance/src/test/java/org/apache/servicecomb/governance/GovernancePropertiesTest.java @@ -47,17 +47,17 @@ import org.apache.servicecomb.governance.policy.RateLimitingPolicy; import org.apache.servicecomb.governance.policy.RetryPolicy; import org.apache.servicecomb.governance.properties.BulkheadProperties; import org.apache.servicecomb.governance.properties.CircuitBreakerProperties; -import org.apache.servicecomb.governance.properties.GovProperties; +import org.apache.servicecomb.governance.properties.GovernanceProperties; import org.apache.servicecomb.governance.properties.MatchProperties; import org.apache.servicecomb.governance.properties.RateLimitProperties; import org.apache.servicecomb.governance.properties.RetryProperties; @RunWith(SpringRunner.class) @ContextConfiguration(locations = "classpath:META-INF/spring/*.xml", initializers = ConfigFileApplicationContextInitializer.class) -public class GovPropertiesTest { +public class GovernancePropertiesTest { @Autowired - private List<GovProperties<? extends AbstractPolicy>> propertiesList; + private List<GovernanceProperties<? extends AbstractPolicy>> propertiesList; @Autowired private MatchProperties matchProperties; @@ -79,7 +79,7 @@ public class GovPropertiesTest { private Map<String, Object> dynamicValues = new HashMap<>(); - public GovPropertiesTest() { + public GovernancePropertiesTest() { System.out.print(1); } diff --git a/governance/src/test/java/org/apache/servicecomb/governance/MockMatchersService.java b/governance/src/test/java/org/apache/servicecomb/governance/MockInvocationContext.java similarity index 58% rename from governance/src/test/java/org/apache/servicecomb/governance/MockMatchersService.java rename to governance/src/test/java/org/apache/servicecomb/governance/MockInvocationContext.java index 1387312..bde9b38 100644 --- a/governance/src/test/java/org/apache/servicecomb/governance/MockMatchersService.java +++ b/governance/src/test/java/org/apache/servicecomb/governance/MockInvocationContext.java @@ -17,17 +17,32 @@ package org.apache.servicecomb.governance; -import java.util.List; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import org.springframework.stereotype.Component; -import org.apache.servicecomb.governance.marker.GovHttpRequest; -import org.apache.servicecomb.governance.service.MatchersService; - @Component -public class MockMatchersService implements MatchersService { +public class MockInvocationContext implements InvocationContext { + private ThreadLocal<Map<String, Boolean>> context = new ThreadLocal<>(); + + @Override + public Map<String, Boolean> getCalculatedMatches() { + Map<String, Boolean> result = context.get(); + if (result == null) { + return Collections.emptyMap(); + } + return result; + } + @Override - public List<String> getMatchedNames(GovHttpRequest govHttpRequest) { - return null; + public void addMatch(String key, Boolean value) { + Map<String, Boolean> result = context.get(); + if (result == null) { + result = new HashMap<>(); + context.set(result); + } + result.put(key, value); } }
