Process the url. Some path variables should be handled and unified.
+ *e.g. collect_item_relation--10200012121-.html will be converted to collect_item_relation.html
+ * + * @param originUrl original url + * @return processed url + */ + String clean(String originUrl); +} diff --git a/sentinel-adapter/sentinel-zuul-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/zuul/fallback/ZuulBlockFallbackManager.java b/sentinel-adapter/sentinel-zuul-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/zuul/fallback/ZuulBlockFallbackManager.java new file mode 100644 index 00000000..2760acff --- /dev/null +++ b/sentinel-adapter/sentinel-zuul-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/zuul/fallback/ZuulBlockFallbackManager.java @@ -0,0 +1,57 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * Licensed 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 com.alibaba.csp.sentinel.adapter.zuul.fallback; + +import java.util.HashMap; +import java.util.Map; + +/** + * This provide fall back class manager. + * + * @author tiger + */ +public class ZuulBlockFallbackManager { + + private static Mapnull
+ * @return the fallback response
+ */
+ BlockResponse fallbackResponse(String route, Throwable cause);
+}
diff --git a/sentinel-adapter/sentinel-zuul-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/zuul/filters/AbstractSentinelFilter.java b/sentinel-adapter/sentinel-zuul-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/zuul/filters/AbstractSentinelFilter.java
new file mode 100644
index 00000000..0becdf53
--- /dev/null
+++ b/sentinel-adapter/sentinel-zuul-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/zuul/filters/AbstractSentinelFilter.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.zuul.filters;
+
+import com.alibaba.csp.sentinel.adapter.zuul.properties.SentinelZuulProperties;
+import com.alibaba.csp.sentinel.util.AssertUtil;
+import com.netflix.zuul.ZuulFilter;
+
+/**
+ * Abstract class for sentinel filters.
+ *
+ * @author tiger
+ */
+public abstract class AbstractSentinelFilter extends ZuulFilter {
+
+ private final SentinelZuulProperties sentinelZuulProperties;
+
+ public SentinelZuulProperties getSentinelZuulProperties() {
+ return sentinelZuulProperties;
+ }
+
+ public AbstractSentinelFilter(SentinelZuulProperties sentinelZuulProperties) {
+ AssertUtil.notNull(sentinelZuulProperties,"SentinelZuulProperties can not be null");
+ this.sentinelZuulProperties = sentinelZuulProperties;
+ }
+
+ @Override
+ public boolean shouldFilter() {
+ return sentinelZuulProperties.isEnabled();
+ }
+
+}
diff --git a/sentinel-adapter/sentinel-zuul-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/zuul/filters/SentinelErrorFilter.java b/sentinel-adapter/sentinel-zuul-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/zuul/filters/SentinelErrorFilter.java
new file mode 100644
index 00000000..dc192dba
--- /dev/null
+++ b/sentinel-adapter/sentinel-zuul-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/zuul/filters/SentinelErrorFilter.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.zuul.filters;
+
+import com.alibaba.csp.sentinel.Tracer;
+import com.alibaba.csp.sentinel.adapter.zuul.properties.SentinelZuulProperties;
+import com.alibaba.csp.sentinel.context.ContextUtil;
+import com.alibaba.csp.sentinel.log.RecordLog;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.netflix.zuul.context.RequestContext;
+import com.netflix.zuul.exception.ZuulException;
+
+import static com.alibaba.csp.sentinel.adapter.zuul.constants.ZuulConstant.ERROR_TYPE;
+
+/**
+ * This filter track routing exception and exit entry;
+ *
+ * @author tiger
+ */
+public class SentinelErrorFilter extends AbstractSentinelFilter {
+
+ public SentinelErrorFilter(SentinelZuulProperties sentinelZuulProperties) {
+ super(sentinelZuulProperties);
+ }
+
+ @Override
+ public String filterType() {
+ return ERROR_TYPE;
+ }
+
+ @Override
+ public boolean shouldFilter() {
+ RequestContext ctx = RequestContext.getCurrentContext();
+ return getSentinelZuulProperties().isEnabled() && ctx.getThrowable() != null;
+ }
+
+ @Override
+ public int filterOrder() {
+ return getSentinelZuulProperties().getOrder().getError();
+ }
+
+ /**
+ * Trace not {@link BlockException} ex.
+ * While loop will exit all entries,
+ * Case serviceId and URL entry twice in {@link SentinelPreFilter}.
+ * The ContextUtil.getContext().getCurEntry() will exit from inner to outer.
+ */
+ @Override
+ public Object run() throws ZuulException {
+ try {
+ RequestContext ctx = RequestContext.getCurrentContext();
+ Throwable throwable = ctx.getThrowable();
+ if (throwable != null) {
+ if (!BlockException.isBlockException(throwable)) {
+ Tracer.trace(throwable.getCause());
+ RecordLog.info("[Sentinel Error Filter] Trace cause", throwable.getCause());
+ }
+ }
+ } finally {
+ while (ContextUtil.getContext() != null && ContextUtil.getContext().getCurEntry() != null) {
+ ContextUtil.getContext().getCurEntry().exit();
+ }
+ ContextUtil.exit();
+ }
+ return null;
+ }
+}
diff --git a/sentinel-adapter/sentinel-zuul-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/zuul/filters/SentinelPostFilter.java b/sentinel-adapter/sentinel-zuul-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/zuul/filters/SentinelPostFilter.java
new file mode 100644
index 00000000..9159489c
--- /dev/null
+++ b/sentinel-adapter/sentinel-zuul-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/zuul/filters/SentinelPostFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.zuul.filters;
+
+import com.alibaba.csp.sentinel.adapter.zuul.properties.SentinelZuulProperties;
+import com.alibaba.csp.sentinel.context.ContextUtil;
+import com.alibaba.csp.sentinel.log.RecordLog;
+import com.netflix.zuul.exception.ZuulException;
+
+import static com.alibaba.csp.sentinel.adapter.zuul.constants.ZuulConstant.POST_TYPE;
+
+/**
+ * This filter do success routing RT statistic and exit {@link com.alibaba.csp.sentinel.Entry}
+ *
+ * @author tiger
+ */
+public class SentinelPostFilter extends AbstractSentinelFilter {
+
+ public SentinelPostFilter(SentinelZuulProperties sentinelZuulProperties) {
+ super(sentinelZuulProperties);
+ }
+
+ @Override
+ public String filterType() {
+ return POST_TYPE;
+ }
+
+ @Override
+ public int filterOrder() {
+ return getSentinelZuulProperties().getOrder().getPost();
+ }
+
+ /**
+ * While loop will exit all entries,
+ * Case serviceId and URL entry twice in {@link SentinelPreFilter}.
+ * The ContextUtil.getContext().getCurEntry() will exit from inner to outer.
+ */
+ @Override
+ public Object run() throws ZuulException {
+ while (ContextUtil.getContext() != null && ContextUtil.getContext().getCurEntry() != null) {
+ ContextUtil.getContext().getCurEntry().exit();
+ }
+ ContextUtil.exit();
+ return null;
+ }
+}
diff --git a/sentinel-adapter/sentinel-zuul-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/zuul/filters/SentinelPreFilter.java b/sentinel-adapter/sentinel-zuul-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/zuul/filters/SentinelPreFilter.java
new file mode 100644
index 00000000..7ef2c787
--- /dev/null
+++ b/sentinel-adapter/sentinel-zuul-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/zuul/filters/SentinelPreFilter.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.zuul.filters;
+
+import com.alibaba.csp.sentinel.EntryType;
+import com.alibaba.csp.sentinel.SphU;
+import com.alibaba.csp.sentinel.adapter.zuul.fallback.*;
+import com.alibaba.csp.sentinel.adapter.zuul.properties.SentinelZuulProperties;
+import com.alibaba.csp.sentinel.adapter.zuul.util.FilterUtil;
+import com.alibaba.csp.sentinel.context.ContextUtil;
+import com.alibaba.csp.sentinel.log.RecordLog;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alibaba.csp.sentinel.util.AssertUtil;
+import com.alibaba.csp.sentinel.util.StringUtil;
+import com.netflix.zuul.context.RequestContext;
+import com.netflix.zuul.exception.ZuulException;
+
+import javax.servlet.http.HttpServletRequest;
+
+import static com.alibaba.csp.sentinel.adapter.zuul.constants.ZuulConstant.PRE_TYPE;
+import static com.alibaba.csp.sentinel.adapter.zuul.constants.ZuulConstant.SERVICE_ID_KEY;
+import static com.alibaba.csp.sentinel.adapter.zuul.constants.ZuulConstant.ZUUL_DEFAULT_CONTEXT;
+
+/**
+ * This pre filter get an entry of resource,the first order is ServiceId, then API Path.
+ * When get a BlockException run fallback logic.
+ *
+ * @author tiger
+ */
+public class SentinelPreFilter extends AbstractSentinelFilter {
+
+ private final UrlCleaner urlCleaner;
+
+ private final RequestOriginParser requestOriginParser;
+
+ public SentinelPreFilter(SentinelZuulProperties sentinelZuulProperties,
+ UrlCleaner urlCleaner,
+ RequestOriginParser requestOriginParser) {
+ super(sentinelZuulProperties);
+ AssertUtil.notNull(urlCleaner, "UrlCleaner can not be null");
+ AssertUtil.notNull(requestOriginParser, "RequestOriginParser can not be null");
+ this.urlCleaner = urlCleaner;
+ this.requestOriginParser = requestOriginParser;
+ }
+
+ @Override
+ public String filterType() {
+ return PRE_TYPE;
+ }
+
+ /**
+ * This run before route filter so we can get more accurate RT time.
+ */
+ @Override
+ public int filterOrder() {
+ return getSentinelZuulProperties().getOrder().getPre();
+ }
+
+ @Override
+ public Object run() throws ZuulException {
+ RequestContext ctx = RequestContext.getCurrentContext();
+ String origin = parseOrigin(ctx.getRequest());
+ String serviceTarget = (String) ctx.get(SERVICE_ID_KEY);
+ // When serviceId blocked first get the service level fallback provider.
+ String fallBackRoute = serviceTarget;
+ try {
+ if (StringUtil.isNotEmpty(serviceTarget)) {
+ RecordLog.info(String.format("[Sentinel Pre Filter] Origin: %s enter ServiceId: %s", origin, serviceTarget));
+ ContextUtil.enter(serviceTarget, origin);
+ SphU.entry(serviceTarget, EntryType.IN);
+ } else {
+ RecordLog.info("[Sentinel Pre Filter] ServiceId is empty");
+ ContextUtil.enter(ZUUL_DEFAULT_CONTEXT, origin);
+ }
+ String uriTarget = FilterUtil.filterTarget(ctx.getRequest());
+ // Clean and unify the URL.
+ // For REST APIs, you have to clean the URL (e.g. `/foo/1` and `/foo/2` -> `/foo/:id`), or
+ // the amount of context and resources will exceed the threshold.
+ uriTarget = urlCleaner.clean(uriTarget);
+ fallBackRoute = uriTarget;
+ RecordLog.info(String.format("[Sentinel Pre Filter] Origin: %s enter Uri Path: %s", origin, uriTarget));
+ SphU.entry(uriTarget, EntryType.IN);
+ } catch (BlockException ex) {
+ RecordLog.warn(String.format("[Sentinel Pre Filter] Block Exception when Origin: %s enter fall back route: %s", origin, fallBackRoute), ex);
+ ZuulBlockFallbackProvider zuulBlockFallbackProvider = ZuulBlockFallbackManager.getFallbackProvider(fallBackRoute);
+ BlockResponse blockResponse = zuulBlockFallbackProvider.fallbackResponse(fallBackRoute, ex);
+ // prevent routing from running
+ ctx.setRouteHost(null);
+ ctx.set(SERVICE_ID_KEY, null);
+ ctx.setResponseBody(blockResponse.toString());
+ }
+ return null;
+ }
+
+ private String parseOrigin(HttpServletRequest request) {
+ return requestOriginParser.parseOrigin(request);
+ }
+}
diff --git a/sentinel-adapter/sentinel-zuul-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/zuul/properties/SentinelZuulProperties.java b/sentinel-adapter/sentinel-zuul-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/zuul/properties/SentinelZuulProperties.java
new file mode 100644
index 00000000..8e7681ed
--- /dev/null
+++ b/sentinel-adapter/sentinel-zuul-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/zuul/properties/SentinelZuulProperties.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.zuul.properties;
+
+import static com.alibaba.csp.sentinel.adapter.zuul.constants.ZuulConstant.SEND_RESPONSE_FILTER_ORDER;
+
+/**
+ * Sentinel Spring Cloud Zuul AutoConfiguration property.
+ *
+ * @author tiger
+ */
+public class SentinelZuulProperties {
+
+ private boolean enabled = false;
+
+ private Order order = new Order();
+
+ public static class Order {
+
+ private int post = SEND_RESPONSE_FILTER_ORDER - 10;
+
+ private int pre = 10000;
+
+ private int error = -1;
+
+ public int getPost() {
+ return post;
+ }
+
+ public void setPost(int post) {
+ this.post = post;
+ }
+
+ public int getPre() {
+ return pre;
+ }
+
+ public void setPre(int pre) {
+ this.pre = pre;
+ }
+
+ public int getError() {
+ return error;
+ }
+
+ public void setError(int error) {
+ this.error = error;
+ }
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public Order getOrder() {
+ return order;
+ }
+
+ public void setOrder(Order order) {
+ this.order = order;
+ }
+}
diff --git a/sentinel-adapter/sentinel-zuul-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/zuul/util/FilterUtil.java b/sentinel-adapter/sentinel-zuul-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/zuul/util/FilterUtil.java
new file mode 100755
index 00000000..cc00ccee
--- /dev/null
+++ b/sentinel-adapter/sentinel-zuul-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/zuul/util/FilterUtil.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.zuul.util;
+
+import com.alibaba.csp.sentinel.util.StringUtil;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * Util class for web servlet filter.
+ * This is same as servlet adapter util class
+ *
+ * @author tiger
+ */
+public final class FilterUtil {
+
+ public static String filterTarget(HttpServletRequest request) {
+ String pathInfo = getResourcePath(request);
+ if (!pathInfo.startsWith("/")) {
+ pathInfo = "/" + pathInfo;
+ }
+
+ if ("/".equals(pathInfo)) {
+ return pathInfo;
+ }
+
+ // Note: pathInfo should be converted to camelCase style.
+ int lastSlashIndex = pathInfo.lastIndexOf("/");
+
+ if (lastSlashIndex >= 0) {
+ pathInfo = pathInfo.substring(0, lastSlashIndex) + "/"
+ + StringUtil.trim(pathInfo.substring(lastSlashIndex + 1));
+ } else {
+ pathInfo = "/" + StringUtil.trim(pathInfo);
+ }
+
+ return pathInfo;
+ }
+
+ private static String getResourcePath(HttpServletRequest request) {
+ String pathInfo = normalizeAbsolutePath(request.getPathInfo(), false);
+ String servletPath = normalizeAbsolutePath(request.getServletPath(), pathInfo.length() != 0);
+
+ return servletPath + pathInfo;
+ }
+
+ private static String normalizeAbsolutePath(String path, boolean removeTrailingSlash) throws IllegalStateException {
+ return normalizePath(path, true, false, removeTrailingSlash);
+ }
+
+ private static String normalizePath(String path, boolean forceAbsolute, boolean forceRelative,
+ boolean removeTrailingSlash) throws IllegalStateException {
+ char[] pathChars = StringUtil.trimToEmpty(path).toCharArray();
+ int length = pathChars.length;
+
+ // Check path and slash.
+ boolean startsWithSlash = false;
+ boolean endsWithSlash = false;
+
+ if (length > 0) {
+ char firstChar = pathChars[0];
+ char lastChar = pathChars[length - 1];
+
+ startsWithSlash = firstChar == '/' || firstChar == '\\';
+ endsWithSlash = lastChar == '/' || lastChar == '\\';
+ }
+
+ StringBuilder buf = new StringBuilder(length);
+ boolean isAbsolutePath = forceAbsolute || !forceRelative && startsWithSlash;
+ int index = startsWithSlash ? 0 : -1;
+ int level = 0;
+
+ if (isAbsolutePath) {
+ buf.append("/");
+ }
+
+ while (index < length) {
+ index = indexOfSlash(pathChars, index + 1, false);
+
+ if (index == length) {
+ break;
+ }
+
+ int nextSlashIndex = indexOfSlash(pathChars, index, true);
+
+ String element = new String(pathChars, index, nextSlashIndex - index);
+ index = nextSlashIndex;
+
+ // Ignore "."
+ if (".".equals(element)) {
+ continue;
+ }
+
+ // Backtrack ".."
+ if ("..".equals(element)) {
+ if (level == 0) {
+ if (isAbsolutePath) {
+ throw new IllegalStateException(path);
+ } else {
+ buf.append("../");
+ }
+ } else {
+ buf.setLength(pathChars[--level]);
+ }
+
+ continue;
+ }
+
+ pathChars[level++] = (char)buf.length();
+ buf.append(element).append('/');
+ }
+
+ // remove the last "/"
+ if (buf.length() > 0) {
+ if (!endsWithSlash || removeTrailingSlash) {
+ buf.setLength(buf.length() - 1);
+ }
+ }
+
+ return buf.toString();
+ }
+
+ private static int indexOfSlash(char[] chars, int beginIndex, boolean slash) {
+ int i = beginIndex;
+
+ for (; i < chars.length; i++) {
+ char ch = chars[i];
+
+ if (slash) {
+ if (ch == '/' || ch == '\\') {
+ break; // if a slash
+ }
+ } else {
+ if (ch != '/' && ch != '\\') {
+ break; // if not a slash
+ }
+ }
+ }
+
+ return i;
+ }
+
+ private FilterUtil() {}
+}
diff --git a/sentinel-adapter/sentinel-zuul-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/zuul/fallback/ZuulBlockFallbackManagerTest.java b/sentinel-adapter/sentinel-zuul-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/zuul/fallback/ZuulBlockFallbackManagerTest.java
new file mode 100644
index 00000000..81425be2
--- /dev/null
+++ b/sentinel-adapter/sentinel-zuul-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/zuul/fallback/ZuulBlockFallbackManagerTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.zuul.fallback;
+
+import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
+import org.junit.Assert;
+import org.junit.Test;
+
+
+/**
+ * @author tiger
+ */
+public class ZuulBlockFallbackManagerTest {
+
+ private String ROUTE = "/test";
+
+ private String DEFAULT_ROUTE = "*";
+
+ class MyNullResponseFallBackProvider implements ZuulBlockFallbackProvider {
+ @Override
+ public String getRoute() {
+ return ROUTE;
+ }
+
+ @Override
+ public BlockResponse fallbackResponse(String route, Throwable cause) {
+ return null;
+ }
+ }
+
+ @Test
+ public void testRegisterProvider() throws Exception {
+ MyNullResponseFallBackProvider myNullResponseFallBackProvider = new MyNullResponseFallBackProvider();
+ ZuulBlockFallbackManager.registerProvider(myNullResponseFallBackProvider);
+ Assert.assertEquals(myNullResponseFallBackProvider.getRoute(), ROUTE);
+ Assert.assertNull(myNullResponseFallBackProvider.fallbackResponse(ROUTE, new FlowException("flow ex")));
+ }
+
+ @Test
+ public void clear() {
+ MyNullResponseFallBackProvider myNullResponseFallBackProvider = new MyNullResponseFallBackProvider();
+ ZuulBlockFallbackManager.registerProvider(myNullResponseFallBackProvider);
+ Assert.assertEquals(myNullResponseFallBackProvider.getRoute(), ROUTE);
+ ZuulBlockFallbackManager.clear();
+ Assert.assertEquals(ZuulBlockFallbackManager.getFallbackProvider(ROUTE).getRoute(),DEFAULT_ROUTE);
+ }
+
+}
\ No newline at end of file
diff --git a/sentinel-adapter/sentinel-zuul-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/zuul/fallback/ZuulBlockFallbackProviderTest.java b/sentinel-adapter/sentinel-zuul-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/zuul/fallback/ZuulBlockFallbackProviderTest.java
new file mode 100644
index 00000000..f701d4a9
--- /dev/null
+++ b/sentinel-adapter/sentinel-zuul-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/zuul/fallback/ZuulBlockFallbackProviderTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.zuul.fallback;
+
+import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author tiger
+ */
+public class ZuulBlockFallbackProviderTest {
+
+ private String ALL_ROUTE = "*";
+
+ @Test
+ public void testGetNullRoute() throws Exception {
+ ZuulBlockFallbackProvider fallbackProvider = ZuulBlockFallbackManager.getFallbackProvider(null);
+ Assert.assertEquals(fallbackProvider.getRoute(), ALL_ROUTE);
+ }
+
+ @Test
+ public void testGetDefaultRoute() throws Exception {
+ ZuulBlockFallbackProvider fallbackProvider = ZuulBlockFallbackManager.getFallbackProvider(ALL_ROUTE);
+ Assert.assertEquals(fallbackProvider.getRoute(), ALL_ROUTE);
+ }
+
+ @Test
+ public void testGetNotInCacheRoute() throws Exception {
+ ZuulBlockFallbackProvider fallbackProvider = ZuulBlockFallbackManager.getFallbackProvider("/not/in");
+ Assert.assertEquals(fallbackProvider.getRoute(), ALL_ROUTE);
+ }
+
+ @Test
+ public void testFlowControlFallbackResponse() throws Exception {
+ ZuulBlockFallbackProvider fallbackProvider = ZuulBlockFallbackManager.getFallbackProvider(ALL_ROUTE);
+ BlockResponse clientHttpResponse = fallbackProvider.fallbackResponse(ALL_ROUTE, new FlowException("flow exception"));
+ Assert.assertEquals(clientHttpResponse.getCode(), 429);
+ }
+
+ @Test
+ public void testRuntimeExceptionFallbackResponse() throws Exception {
+ ZuulBlockFallbackProvider fallbackProvider = ZuulBlockFallbackManager.getFallbackProvider(ALL_ROUTE);
+ BlockResponse clientHttpResponse = fallbackProvider.fallbackResponse(ALL_ROUTE, new RuntimeException());
+ Assert.assertEquals(clientHttpResponse.getCode(), 500);
+ }
+}
\ No newline at end of file
diff --git a/sentinel-adapter/sentinel-zuul-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/zuul/filters/SentinelErrorFilterTest.java b/sentinel-adapter/sentinel-zuul-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/zuul/filters/SentinelErrorFilterTest.java
new file mode 100644
index 00000000..8f2bca89
--- /dev/null
+++ b/sentinel-adapter/sentinel-zuul-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/zuul/filters/SentinelErrorFilterTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.zuul.filters;
+
+import com.alibaba.csp.sentinel.adapter.zuul.properties.SentinelZuulProperties;
+import com.netflix.zuul.context.RequestContext;
+import org.junit.Assert;
+import org.junit.Test;
+
+import static com.alibaba.csp.sentinel.adapter.zuul.constants.ZuulConstant.ERROR_TYPE;
+
+/**
+ * @author tiger
+ */
+public class SentinelErrorFilterTest {
+ @Test
+ public void testFilterType() throws Exception {
+ SentinelZuulProperties properties = new SentinelZuulProperties();
+ SentinelErrorFilter sentinelErrorFilter = new SentinelErrorFilter(properties);
+ Assert.assertEquals(sentinelErrorFilter.filterType(), ERROR_TYPE);
+ }
+
+ @Test
+ public void testShouldFilter() {
+ SentinelZuulProperties properties = new SentinelZuulProperties();
+ Assert.assertFalse(properties.isEnabled());
+ properties.setEnabled(true);
+ SentinelErrorFilter sentinelErrorFilter = new SentinelErrorFilter(properties);
+ RequestContext ctx = RequestContext.getCurrentContext();
+ ctx.setThrowable(new RuntimeException());
+ Assert.assertTrue(sentinelErrorFilter.shouldFilter());
+ }
+
+ @Test
+ public void testRun() throws Exception {
+ SentinelZuulProperties properties = new SentinelZuulProperties();
+ SentinelErrorFilter sentinelErrorFilter = new SentinelErrorFilter(properties);
+ Object result = sentinelErrorFilter.run();
+ Assert.assertNull(result);
+ }
+
+}
\ No newline at end of file
diff --git a/sentinel-adapter/sentinel-zuul-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/zuul/filters/SentinelPostFilterTest.java b/sentinel-adapter/sentinel-zuul-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/zuul/filters/SentinelPostFilterTest.java
new file mode 100644
index 00000000..6ccd6cae
--- /dev/null
+++ b/sentinel-adapter/sentinel-zuul-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/zuul/filters/SentinelPostFilterTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.zuul.filters;
+
+import com.alibaba.csp.sentinel.adapter.zuul.properties.SentinelZuulProperties;
+import org.junit.Assert;
+import org.junit.Test;
+
+import static com.alibaba.csp.sentinel.adapter.zuul.constants.ZuulConstant.POST_TYPE;
+
+/**
+ * @author tiger
+ */
+public class SentinelPostFilterTest {
+
+ @Test
+ public void testFilterType() throws Exception {
+ SentinelZuulProperties properties = new SentinelZuulProperties();
+ SentinelPostFilter sentinelPostFilter = new SentinelPostFilter(properties);
+ Assert.assertEquals(sentinelPostFilter.filterType(), POST_TYPE);
+ }
+
+ @Test
+ public void testRun() throws Exception {
+ SentinelZuulProperties properties = new SentinelZuulProperties();
+ SentinelPostFilter sentinelPostFilter = new SentinelPostFilter(properties);
+ Object result = sentinelPostFilter.run();
+ Assert.assertNull(result);
+ }
+
+}
\ No newline at end of file
diff --git a/sentinel-adapter/sentinel-zuul-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/zuul/filters/SentinelPreFilterTest.java b/sentinel-adapter/sentinel-zuul-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/zuul/filters/SentinelPreFilterTest.java
new file mode 100644
index 00000000..ab71e5cf
--- /dev/null
+++ b/sentinel-adapter/sentinel-zuul-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/zuul/filters/SentinelPreFilterTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.zuul.filters;
+
+import com.alibaba.csp.sentinel.adapter.zuul.fallback.DefaultRequestOriginParser;
+import com.alibaba.csp.sentinel.adapter.zuul.fallback.RequestOriginParser;
+import com.alibaba.csp.sentinel.adapter.zuul.fallback.UrlCleaner;
+import com.alibaba.csp.sentinel.adapter.zuul.properties.SentinelZuulProperties;
+import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
+import com.netflix.zuul.context.RequestContext;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import javax.servlet.http.HttpServletRequest;
+
+import static com.alibaba.csp.sentinel.adapter.zuul.constants.ZuulConstant.PRE_TYPE;
+import static com.alibaba.csp.sentinel.adapter.zuul.constants.ZuulConstant.SERVICE_ID_KEY;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.when;
+
+/**
+ * @author tiger
+ */
+public class SentinelPreFilterTest {
+
+ private String SERVICE_ID = "servicea";
+
+ private String URI = "/servicea/test";
+
+ @Mock
+ private HttpServletRequest httpServletRequest;
+
+ @Mock
+ private UrlCleaner urlCleaner;
+
+ private final RequestOriginParser requestOriginParser = new DefaultRequestOriginParser();
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(httpServletRequest.getContextPath()).thenReturn("");
+ when(httpServletRequest.getPathInfo()).thenReturn(URI);
+ RequestContext requestContext = new RequestContext();
+ requestContext.set(SERVICE_ID_KEY, SERVICE_ID);
+ requestContext.setRequest(httpServletRequest);
+ RequestContext.testSetCurrentContext(requestContext);
+ }
+
+ @Test
+ public void testFilterType() throws Exception {
+ SentinelZuulProperties properties = new SentinelZuulProperties();
+ SentinelPreFilter sentinelPreFilter = new SentinelPreFilter(properties, urlCleaner, requestOriginParser);
+ Assert.assertEquals(sentinelPreFilter.filterType(), PRE_TYPE);
+ }
+
+ @Test
+ public void testRun() throws Exception {
+ RequestContext ctx = RequestContext.getCurrentContext();
+ SentinelZuulProperties properties = new SentinelZuulProperties();
+ SentinelPreFilter sentinelPreFilter = new SentinelPreFilter(properties, urlCleaner, requestOriginParser);
+ given(urlCleaner.clean(URI)).willReturn(URI);
+ sentinelPreFilter.run();
+ Assert.assertNull(ctx.getRouteHost());
+ Assert.assertEquals(ctx.get(SERVICE_ID_KEY), SERVICE_ID);
+ }
+
+ @Test
+ public void testServiceFallBackRun() throws Exception {
+ RequestContext ctx = RequestContext.getCurrentContext();
+ SentinelZuulProperties properties = new SentinelZuulProperties();
+ properties.setEnabled(true);
+ SentinelPreFilter sentinelPreFilter = new SentinelPreFilter(properties, urlCleaner, requestOriginParser);
+
+ given(urlCleaner.clean(URI)).willAnswer(
+ new Answer