Sync code and bump version to 1.6.0 master
authorEric Zhao <sczyh16@gmail.com>
Thu, 25 Apr 2019 09:10:01 +0000 (17:10 +0800)
committerEric Zhao <sczyh16@gmail.com>
Thu, 25 Apr 2019 09:10:01 +0000 (17:10 +0800)
Signed-off-by: Eric Zhao <sczyh16@gmail.com>
25 files changed:
README.md
pom.xml
src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/AbstractDubboFilter.java [deleted file]
src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboAppContextFilter.java
src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboUtils.java
src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboConsumerFilter.java
src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboProviderFilter.java
src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DefaultDubboFallback.java
src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DubboFallback.java
src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DubboFallbackRegistry.java
src/main/resources/META-INF/dubbo/org.apache.dubbo.rpc.Filter [moved from src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter with 88% similarity]
src/test/java/com/alibaba/csp/sentinel/BaseTest.java [new file with mode: 0644]
src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DemoService.java [deleted file]
src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboAppContextFilterTest.java [new file with mode: 0644]
src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboConsumerTest.java [deleted file]
src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboProviderTest.java [deleted file]
src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboUtilsTest.java [new file with mode: 0644]
src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboConsumerFilterTest.java [new file with mode: 0644]
src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboProviderFilterTest.java [new file with mode: 0644]
src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DubboFallbackRegistryTest.java [new file with mode: 0644]
src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/provider/DemoService.java [new file with mode: 0644]
src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/provider/DemoServiceImpl.java [deleted file]
src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/provider/impl/DemoServiceImpl.java [new file with mode: 0644]
src/test/resources/spring-dubbo-consumer-filter.xml
src/test/resources/spring-dubbo-provider-filter.xml

index da6bd23e32e9af307080581e6d3f37b3c8752087..fe97e9f48bba31b448bd535c1e47e64d39b94bcd 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,23 +1,23 @@
-# Sentinel Dubbo Adapter
+# Sentinel Apache Dubbo Adapter
 
-> Note: 中文文档请见[此处](https://github.com/alibaba/Sentinel/wiki/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6%E7%9A%84%E9%80%82%E9%85%8D#dubbo)。
+> Note: 中文文档请见[此处](https://github.com/alibaba/Sentinel/wiki/主流框架的适配#dubbo)。
 
 Sentinel Dubbo Adapter provides service consumer filter and provider filter
-for [Dubbo](http://dubbo.io/) services. 
+for [Apache Dubbo](https://dubbo.apache.org/en-us/) services.
+
+**Note: This adapter only supports Apache Dubbo 2.7.x and above.** For legacy `com.alibaba:dubbo` 2.6.x,
+please use `sentinel-dubbo-adapter` module instead.
 
 To use Sentinel Dubbo Adapter, you can simply add the following dependency to your `pom.xml`:
 
 ```xml
 <dependency>
     <groupId>com.alibaba.csp</groupId>
-    <artifactId>sentinel-dubbo-adapter</artifactId>
+    <artifactId>sentinel-apache-dubbo-adapter</artifactId>
     <version>x.y.z</version>
 </dependency>
 ```
 
-> Note: currently this adapter is not compatible with Dubbo 2.7.x due to its package renaming.
-We are working to support the latest Dubbo version.
-
 The Sentinel filters are **enabled by default**. Once you add the dependency,
 the Dubbo services and methods will become protected resources in Sentinel,
 which can leverage Sentinel's flow control and guard ability when rules are configured.
@@ -31,7 +31,7 @@ If you don't want the filters enabled, you can manually disable them. For exampl
 <dubbo:provider filter="-sentinel.dubbo.provider.filter"/>
 ```
 
-For more details of Dubbo filter, see [here](https://dubbo.incubator.apache.org/#/docs/dev/impls/filter.md?lang=en-us).
+For more details of Dubbo filter, see [here](http://dubbo.apache.org/en-us/docs/dev/impls/filter.html).
 
 ## Dubbo resources
 
@@ -65,4 +65,4 @@ flow control, degrade or system load protection. You can implement your own `Dub
 and then register to `DubboFallbackRegistry`. If no fallback is configured, Sentinel will wrap the `BlockException`
 then directly throw it out.
 
-Besides, we can also leverage [Dubbo mock mechanism](http://dubbo.apache.org/#!/docs/user/demos/local-mock.md?lang=en-us) to provide fallback implementation of degraded Dubbo services.
\ No newline at end of file
+Besides, we can also leverage [Dubbo mock mechanism](http://dubbo.apache.org/en-us/docs/user/demos/local-mock.html) to provide fallback implementation of degraded Dubbo services.
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 3ed33aaaead4e010305dd0fa9d453993b0c90121..dfd08bb98d9af657784065096df2d9fc8978d33d 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -4,33 +4,51 @@
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
 
-    <parent>
-        <groupId>com.alibaba.csp</groupId>
-        <artifactId>sentinel-adapter</artifactId>
-        <version>1.4.2</version>
-    </parent>
-    <artifactId>sentinel-dubbo-adapter</artifactId>
+    <groupId>com.alibaba.csp</groupId>
+    <artifactId>sentinel-apache-dubbo-adapter</artifactId>
+    <version>1.6.0</version>
     <packaging>jar</packaging>
 
+    <properties>
+        <java.source.version>1.8</java.source.version>
+        <java.target.version>1.8</java.target.version>
+
+        <sentinel.version>1.6.0</sentinel.version>
+        <apache.dubbo.version>2.7.1</apache.dubbo.version>
+
+        <junit.version>4.12</junit.version>
+        <mockito.version>2.21.0</mockito.version>
+    </properties>
+
     <dependencies>
         <dependency>
             <groupId>com.alibaba.csp</groupId>
             <artifactId>sentinel-core</artifactId>
+            <version>${sentinel.version}</version>
         </dependency>
         <dependency>
-            <groupId>com.alibaba</groupId>
+            <groupId>org.apache.dubbo</groupId>
             <artifactId>dubbo</artifactId>
+            <version>${apache.dubbo.version}</version>
             <scope>provided</scope>
         </dependency>
 
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
+            <version>${junit.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <version>${mockito.version}</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>com.alibaba</groupId>
             <artifactId>fastjson</artifactId>
+            <version>1.2.57</version>
             <scope>test</scope>
         </dependency>
     </dependencies>
diff --git a/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/AbstractDubboFilter.java b/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/AbstractDubboFilter.java
deleted file mode 100755 (executable)
index 2c5b077..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.dubbo;
-
-import com.alibaba.dubbo.rpc.Filter;
-import com.alibaba.dubbo.rpc.Invocation;
-import com.alibaba.dubbo.rpc.Invoker;
-
-/**
- * @author leyou
- */
-abstract class AbstractDubboFilter implements Filter {
-
-    protected String getResourceName(Invoker<?> invoker, Invocation invocation) {
-        StringBuilder buf = new StringBuilder(64);
-        buf.append(invoker.getInterface().getName())
-            .append(":")
-            .append(invocation.getMethodName())
-            .append("(");
-        boolean isFirst = true;
-        for (Class<?> clazz : invocation.getParameterTypes()) {
-            if (!isFirst) {
-                buf.append(",");
-            }
-            buf.append(clazz.getName());
-            isFirst = false;
-        }
-        buf.append(")");
-        return buf.toString();
-    }
-}
index ceae979d53854d97a52a6010ffeaf94168e03f1f..97ae51bac38f9c77bdfe625566bc4b681c8268a8 100644 (file)
  */
 package com.alibaba.csp.sentinel.adapter.dubbo;
 
-import com.alibaba.dubbo.common.Constants;
-import com.alibaba.dubbo.common.extension.Activate;
-import com.alibaba.dubbo.rpc.Filter;
-import com.alibaba.dubbo.rpc.Invocation;
-import com.alibaba.dubbo.rpc.Invoker;
-import com.alibaba.dubbo.rpc.Result;
-import com.alibaba.dubbo.rpc.RpcContext;
-import com.alibaba.dubbo.rpc.RpcException;
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.rpc.Filter;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Result;
+import org.apache.dubbo.rpc.RpcContext;
+import org.apache.dubbo.rpc.RpcException;
 
 /**
  * Puts current consumer's application name in the attachment of each invocation.
@@ -36,7 +36,7 @@ public class DubboAppContextFilter implements Filter {
     public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
         String application = invoker.getUrl().getParameter(Constants.APPLICATION_KEY);
         if (application != null) {
-            RpcContext.getContext().setAttachment(DubboUtils.DUBBO_APPLICATION_KEY, application);
+            RpcContext.getContext().setAttachment(DubboUtils.SENTINEL_DUBBO_APPLICATION_KEY, application);
         }
         return invoker.invoke(invocation);
     }
index f633e9e0f17a74e2f36ebb994e05c4e8da0651cc..03a494f5854c477326448332b742c15a99e02dd8 100644 (file)
  */
 package com.alibaba.csp.sentinel.adapter.dubbo;
 
-import com.alibaba.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
 
 /**
  * @author Eric Zhao
  */
 public final class DubboUtils {
 
-    public static final String DUBBO_APPLICATION_KEY = "dubboApplication";
+    public static final String SENTINEL_DUBBO_APPLICATION_KEY = "dubboApplication";
 
     public static String getApplication(Invocation invocation, String defaultValue) {
         if (invocation == null || invocation.getAttachments() == null) {
             throw new IllegalArgumentException("Bad invocation instance");
         }
-        return invocation.getAttachment(DUBBO_APPLICATION_KEY, defaultValue);
+        return invocation.getAttachment(SENTINEL_DUBBO_APPLICATION_KEY, defaultValue);
+    }
+
+    public static String getResourceName(Invoker<?> invoker, Invocation invocation) {
+        StringBuilder buf = new StringBuilder(64);
+        buf.append(invoker.getInterface().getName())
+            .append(":")
+            .append(invocation.getMethodName())
+            .append("(");
+        boolean isFirst = true;
+        for (Class<?> clazz : invocation.getParameterTypes()) {
+            if (!isFirst) {
+                buf.append(",");
+            }
+            buf.append(clazz.getName());
+            isFirst = false;
+        }
+        buf.append(")");
+        return buf.toString();
     }
 
     private DubboUtils() {}
index 85b268d812242f3bba9445517a0b262cc4632c0d..6ca0d6764a703823bc36086bf01844c389845e44 100755 (executable)
@@ -20,15 +20,15 @@ import com.alibaba.csp.sentinel.EntryType;
 import com.alibaba.csp.sentinel.SphU;
 import com.alibaba.csp.sentinel.Tracer;
 import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallbackRegistry;
-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.dubbo.common.extension.Activate;
-import com.alibaba.dubbo.rpc.Filter;
-import com.alibaba.dubbo.rpc.Invocation;
-import com.alibaba.dubbo.rpc.Invoker;
-import com.alibaba.dubbo.rpc.Result;
-import com.alibaba.dubbo.rpc.RpcException;
+
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.rpc.Filter;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Result;
+import org.apache.dubbo.rpc.RpcException;
 
 /**
  * <p>Dubbo service consumer filter for Sentinel. Auto activated by default.</p>
@@ -38,14 +38,14 @@ import com.alibaba.dubbo.rpc.RpcException;
  * &lt;dubbo:consumer filter="-sentinel.dubbo.consumer.filter"/&gt;
  * </pre>
  *
- * @author leyou
+ * @author Carpenter Lee
  * @author Eric Zhao
  */
 @Activate(group = "consumer")
-public class SentinelDubboConsumerFilter extends AbstractDubboFilter implements Filter {
+public class SentinelDubboConsumerFilter implements Filter {
 
     public SentinelDubboConsumerFilter() {
-        RecordLog.info("Sentinel Dubbo consumer filter initialized");
+        RecordLog.info("Sentinel Apache Dubbo consumer filter initialized");
     }
 
     @Override
@@ -53,21 +53,23 @@ public class SentinelDubboConsumerFilter extends AbstractDubboFilter implements
         Entry interfaceEntry = null;
         Entry methodEntry = null;
         try {
-            String resourceName = getResourceName(invoker, invocation);
-            ContextUtil.enter(resourceName);
+            String resourceName = DubboUtils.getResourceName(invoker, invocation);
             interfaceEntry = SphU.entry(invoker.getInterface().getName(), EntryType.OUT);
             methodEntry = SphU.entry(resourceName, EntryType.OUT);
 
             Result result = invoker.invoke(invocation);
             if (result.hasException()) {
+                Throwable e = result.getException();
                 // Record common exception.
-                Tracer.trace(result.getException());
+                Tracer.traceEntry(e, interfaceEntry);
+                Tracer.traceEntry(e, methodEntry);
             }
             return result;
         } catch (BlockException e) {
             return DubboFallbackRegistry.getConsumerFallback().handle(invoker, invocation, e);
         } catch (RpcException e) {
-            Tracer.trace(e);
+            Tracer.traceEntry(e, interfaceEntry);
+            Tracer.traceEntry(e, methodEntry);
             throw e;
         } finally {
             if (methodEntry != null) {
@@ -76,7 +78,6 @@ public class SentinelDubboConsumerFilter extends AbstractDubboFilter implements
             if (interfaceEntry != null) {
                 interfaceEntry.exit();
             }
-            ContextUtil.exit();
         }
     }
 }
index c82afb8bb7249298fbef95d2a362c88d69ca00b0..2020832a0b341ef7fec6741c22c28bfd5cd30c29 100755 (executable)
@@ -23,30 +23,31 @@ import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallbackRegistry;
 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.slots.block.SentinelRpcException;
-import com.alibaba.dubbo.common.extension.Activate;
-import com.alibaba.dubbo.rpc.Filter;
-import com.alibaba.dubbo.rpc.Invocation;
-import com.alibaba.dubbo.rpc.Invoker;
-import com.alibaba.dubbo.rpc.Result;
-import com.alibaba.dubbo.rpc.RpcException;
+
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.rpc.Filter;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Result;
+import org.apache.dubbo.rpc.RpcException;
 
 /**
- * <p>Dubbo service provider filter for Sentinel. Auto activated by default.</p>
+ * <p>Apache Dubbo service provider filter that enables integration with Sentinel. Auto activated by default.</p>
+ * <p>Note: this only works for Apache Dubbo 2.7.x or above version.</p>
  *
  * If you want to disable the provider filter, you can configure:
  * <pre>
  * &lt;dubbo:provider filter="-sentinel.dubbo.provider.filter"/&gt;
  * </pre>
  *
- * @author leyou
+ * @author Carpenter Lee
  * @author Eric Zhao
  */
 @Activate(group = "provider")
-public class SentinelDubboProviderFilter extends AbstractDubboFilter implements Filter {
+public class SentinelDubboProviderFilter implements Filter {
 
     public SentinelDubboProviderFilter() {
-        RecordLog.info("Sentinel Dubbo provider filter initialized");
+        RecordLog.info("Sentinel Apache Dubbo provider filter initialized");
     }
 
     @Override
@@ -57,21 +58,27 @@ public class SentinelDubboProviderFilter extends AbstractDubboFilter implements
         Entry interfaceEntry = null;
         Entry methodEntry = null;
         try {
-            String resourceName = getResourceName(invoker, invocation);
+            String resourceName = DubboUtils.getResourceName(invoker, invocation);
             String interfaceName = invoker.getInterface().getName();
+            // Only need to create entrance context at provider side, as context will take effect
+            // at entrance of invocation chain only (for inbound traffic).
             ContextUtil.enter(resourceName, application);
             interfaceEntry = SphU.entry(interfaceName, EntryType.IN);
             methodEntry = SphU.entry(resourceName, EntryType.IN, 1, invocation.getArguments());
 
             Result result = invoker.invoke(invocation);
             if (result.hasException()) {
-                Tracer.trace(result.getException());
+                Throwable e = result.getException();
+                // Record common exception.
+                Tracer.traceEntry(e, interfaceEntry);
+                Tracer.traceEntry(e, methodEntry);
             }
             return result;
         } catch (BlockException e) {
             return DubboFallbackRegistry.getProviderFallback().handle(invoker, invocation, e);
         } catch (RpcException e) {
-            Tracer.trace(e);
+            Tracer.traceEntry(e, interfaceEntry);
+            Tracer.traceEntry(e, methodEntry);
             throw e;
         } finally {
             if (methodEntry != null) {
index e41b51bc86dd1d0bdbe8722a0048298149c2810a..8a4659f7be3862cb25849b0f4eac468744eb3fe8 100644 (file)
@@ -17,13 +17,13 @@ package com.alibaba.csp.sentinel.adapter.dubbo.fallback;
 
 import com.alibaba.csp.sentinel.slots.block.BlockException;
 import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;
-import com.alibaba.dubbo.rpc.Invocation;
-import com.alibaba.dubbo.rpc.Invoker;
-import com.alibaba.dubbo.rpc.Result;
+
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Result;
 
 /**
  * @author Eric Zhao
- * @since 0.1.1
  */
 public class DefaultDubboFallback implements DubboFallback {
 
index f529ae3b025e16b44097fc915b87e9b0fcf1ddef..133232c38458e5d83f340de0e07ed458560d9d58 100644 (file)
 package com.alibaba.csp.sentinel.adapter.dubbo.fallback;
 
 import com.alibaba.csp.sentinel.slots.block.BlockException;
-import com.alibaba.dubbo.rpc.Invocation;
-import com.alibaba.dubbo.rpc.Invoker;
-import com.alibaba.dubbo.rpc.Result;
+
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Result;
 
 /**
  * Fallback handler for Dubbo services.
  *
  * @author Eric Zhao
- * @since 0.1.1
  */
+@FunctionalInterface
 public interface DubboFallback {
 
     /**
index 9f87e61435efe4077bcaf5e6bd073c1307ebb65b..78c3a0b191ce97ea9f26c93a807ea2494433067e 100644 (file)
  */
 package com.alibaba.csp.sentinel.adapter.dubbo.fallback;
 
+import com.alibaba.csp.sentinel.util.AssertUtil;
+
 /**
- * Global fallback registry for Dubbo.
+ * <p>Global fallback registry for Dubbo.</p>
  *
- * Note: Degrading is mainly designed for consumer. The provider should not
+ * <p>
+ * Note: Circuit breaking is mainly designed for consumer. The provider should not
  * give fallback result in most circumstances.
+ * </p>
  *
  * @author Eric Zhao
- * @since 0.1.1
  */
 public final class DubboFallbackRegistry {
 
@@ -34,6 +37,7 @@ public final class DubboFallbackRegistry {
     }
 
     public static void setConsumerFallback(DubboFallback consumerFallback) {
+        AssertUtil.notNull(consumerFallback, "consumerFallback cannot be null");
         DubboFallbackRegistry.consumerFallback = consumerFallback;
     }
 
@@ -42,6 +46,7 @@ public final class DubboFallbackRegistry {
     }
 
     public static void setProviderFallback(DubboFallback providerFallback) {
+        AssertUtil.notNull(providerFallback, "providerFallback cannot be null");
         DubboFallbackRegistry.providerFallback = providerFallback;
     }
 
similarity index 88%
rename from src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter
rename to src/main/resources/META-INF/dubbo/org.apache.dubbo.rpc.Filter
index af7c961b746e01e492b81da29706bc7173f998b4..292a4b2591f8e027a061ccaf53662838b60bbd9c 100755 (executable)
@@ -1,3 +1,3 @@
 sentinel.dubbo.provider.filter=com.alibaba.csp.sentinel.adapter.dubbo.SentinelDubboProviderFilter
 sentinel.dubbo.consumer.filter=com.alibaba.csp.sentinel.adapter.dubbo.SentinelDubboConsumerFilter
-dubbo.application.context.name.filter=com.alibaba.csp.sentinel.adapter.dubbo.DubboAppContextFilter
\ No newline at end of file
+dubbo.application.context.name.filter=com.alibaba.csp.sentinel.adapter.dubbo.DubboAppContextFilter
diff --git a/src/test/java/com/alibaba/csp/sentinel/BaseTest.java b/src/test/java/com/alibaba/csp/sentinel/BaseTest.java
new file mode 100644 (file)
index 0000000..a61f3b4
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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;
+
+import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
+
+import org.apache.dubbo.rpc.RpcContext;
+
+/**
+ * Base test class, provide common methods for subClass
+ * The package is same as CtSph, to call CtSph.resetChainMap() method for test
+ *
+ * Note: Only for test. DO NOT USE IN PRODUCTION!
+ *
+ * @author cdfive
+ */
+public class BaseTest {
+
+    /**
+     * Clean up resources for context, clusterNodeMap, processorSlotChainMap
+     */
+    protected static void cleanUpAll() {
+        RpcContext.removeContext();
+        ClusterBuilderSlot.getClusterNodeMap().clear();
+        CtSph.resetChainMap();
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DemoService.java b/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DemoService.java
deleted file mode 100755 (executable)
index 8ccc4a0..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.alibaba.csp.sentinel.adapter.dubbo;
-
-/**
- * @author leyou
- */
-public interface DemoService {
-    String sayHello(String name, int n);
-}
diff --git a/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboAppContextFilterTest.java b/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboAppContextFilterTest.java
new file mode 100644 (file)
index 0000000..1f461ea
--- /dev/null
@@ -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.dubbo;
+
+import com.alibaba.csp.sentinel.BaseTest;
+import com.alibaba.csp.sentinel.adapter.dubbo.DubboAppContextFilter;
+import com.alibaba.csp.sentinel.adapter.dubbo.DubboUtils;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcContext;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * @author cdfive
+ */
+public class DubboAppContextFilterTest extends BaseTest {
+
+    private DubboAppContextFilter filter = new DubboAppContextFilter();
+
+    @Before
+    public void setUp() {
+        cleanUpAll();
+    }
+
+    @After
+    public void cleanUp() {
+        cleanUpAll();
+    }
+
+    @Test
+    public void testInvokeApplicationKey() {
+        Invoker invoker = mock(Invoker.class);
+        Invocation invocation = mock(Invocation.class);
+        URL url = URL.valueOf("test://test:111/test?application=serviceA");
+        when(invoker.getUrl()).thenReturn(url);
+
+        filter.invoke(invoker, invocation);
+        verify(invoker).invoke(invocation);
+
+        String application = RpcContext.getContext().getAttachment(DubboUtils.SENTINEL_DUBBO_APPLICATION_KEY);
+        assertEquals("serviceA", application);
+    }
+
+    @Test
+    public void testInvokeNullApplicationKey() {
+        Invoker invoker = mock(Invoker.class);
+        Invocation invocation = mock(Invocation.class);
+        URL url = URL.valueOf("test://test:111/test?application=");
+        when(invoker.getUrl()).thenReturn(url);
+
+        filter.invoke(invoker, invocation);
+        verify(invoker).invoke(invocation);
+
+        String application = RpcContext.getContext().getAttachment(DubboUtils.SENTINEL_DUBBO_APPLICATION_KEY);
+        assertNull(application);
+    }
+}
diff --git a/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboConsumerTest.java b/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboConsumerTest.java
deleted file mode 100755 (executable)
index 4ba0a4d..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-package com.alibaba.csp.sentinel.adapter.dubbo;
-
-import java.util.Arrays;
-
-import com.alibaba.csp.sentinel.node.ClusterNode;
-import com.alibaba.csp.sentinel.slots.block.RuleConstant;
-import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;
-import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
-import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
-import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.springframework.context.support.ClassPathXmlApplicationContext;
-
-/**
- * 运行该用例的时候需要加入JVM参数:-Djava.net.preferIPv4Stack=true,
- * 否则可能会抛出{@code java.lang.IllegalStateException: Can't assign requested address}
- *
- * @author leyou
- */
-public class DubboConsumerTest {
-    private final String resource = "com.alibaba.csp.sentinel.adapter.dubbo.DemoService:sayHello(java.lang.String,int)";
-    private final String interfaceResource = "com.alibaba.csp.sentinel.adapter.dubbo.DemoService";
-    private ClassPathXmlApplicationContext context;
-
-    @Before
-    public void init() {
-        context = new ClassPathXmlApplicationContext(
-            new String[] {"spring-dubbo-consumer-filter.xml"});
-        context.start();
-    }
-
-    @Test
-    public void testConsumerFilter() throws Exception {
-        DemoService demoService = (DemoService)context.getBean("demoService");
-        String result = demoService.sayHello("Test dubbo consumer filter", 2);
-        System.out.println("result=" + result);
-        ClusterNode node = ClusterBuilderSlot.getClusterNode(resource);
-        Assert.assertNotNull(node);
-    }
-
-    @Test(expected = SentinelRpcException.class)
-    public void testConsumerBlock() throws Exception {
-        FlowRule flowRule = new FlowRule();
-        flowRule.setResource(resource);
-        flowRule.setCount(10);
-        flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
-        flowRule.setLimitApp("default");
-        FlowRuleManager.loadRules(Arrays.asList(flowRule));
-
-        DemoService demoService = (DemoService)context.getBean("demoService");
-        for (int i = 0; i < 100; i++) {
-            demoService.sayHello("Test dubbo consumer filter", 2);
-        }
-    }
-
-    @Test(expected = SentinelRpcException.class)
-    public void testConsumerBlock2() throws Exception {
-        FlowRule flowRule = new FlowRule();
-        flowRule.setResource(interfaceResource);
-        flowRule.setCount(10);
-        flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
-        flowRule.setLimitApp("default");
-        FlowRuleManager.loadRules(Arrays.asList(flowRule));
-
-        DemoService demoService = (DemoService)context.getBean("demoService");
-        for (int i = 0; i < 100; i++) {
-            demoService.sayHello("Test dubbo consumer filter", 2);
-        }
-    }
-
-}
diff --git a/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboProviderTest.java b/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboProviderTest.java
deleted file mode 100755 (executable)
index 8c4657e..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.alibaba.csp.sentinel.adapter.dubbo;
-
-import com.alibaba.csp.sentinel.node.ClusterNode;
-import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.springframework.context.support.ClassPathXmlApplicationContext;
-
-/**
- * 运行该用例的时候需要加入JVM参数:-Djava.net.preferIPv4Stack=true,
- * 否则可能会抛出{@code java.lang.IllegalStateException: Can't assign requested address}
- *
- * @author leyou
- */
-public class DubboProviderTest {
-
-    private final String resource = "com.alibaba.csp.sentinel.adapter.dubbo.DemoService:sayHello(java.lang.String,int)";
-
-    @Test
-    public void testProviderFilter() throws Exception {
-        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
-            new String[] {"spring-dubbo-provider-filter.xml"});
-        context.start();
-        DemoService demoService = (DemoService)context.getBean("demoService");
-        String result = demoService.sayHello("Test dubbo provider filter", 1);
-        System.out.println("result=" + result);
-        ClusterNode node = ClusterBuilderSlot.getClusterNode(resource);
-        Thread.sleep(1000 * 60 * 100);
-        Assert.assertNotNull(node);
-    }
-}
diff --git a/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboUtilsTest.java b/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboUtilsTest.java
new file mode 100644 (file)
index 0000000..e06c85d
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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.dubbo;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+
+import com.alibaba.csp.sentinel.adapter.dubbo.DubboUtils;
+import com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService;
+
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * @author cdfive
+ */
+public class DubboUtilsTest {
+
+    @Test
+    public void testGetApplication() {
+        Invocation invocation = mock(Invocation.class);
+        when(invocation.getAttachments()).thenReturn(new HashMap<>());
+        when(invocation.getAttachment(DubboUtils.SENTINEL_DUBBO_APPLICATION_KEY, ""))
+            .thenReturn("consumerA");
+
+        String application = DubboUtils.getApplication(invocation, "");
+        verify(invocation).getAttachment(DubboUtils.SENTINEL_DUBBO_APPLICATION_KEY, "");
+
+        assertEquals("consumerA", application);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetApplicationNoAttachments() {
+        Invocation invocation = mock(Invocation.class);
+        when(invocation.getAttachments()).thenReturn(null);
+        when(invocation.getAttachment(DubboUtils.SENTINEL_DUBBO_APPLICATION_KEY, ""))
+            .thenReturn("consumerA");
+
+        DubboUtils.getApplication(invocation, "");
+
+        fail("No attachments in invocation, IllegalArgumentException should be thrown!");
+    }
+
+    @Test
+    public void testGetResourceName() {
+        Invoker invoker = mock(Invoker.class);
+        when(invoker.getInterface()).thenReturn(DemoService.class);
+
+        Invocation invocation = mock(Invocation.class);
+        Method method = DemoService.class.getMethods()[0];
+        when(invocation.getMethodName()).thenReturn(method.getName());
+        when(invocation.getParameterTypes()).thenReturn(method.getParameterTypes());
+
+        String resourceName = DubboUtils.getResourceName(invoker, invocation);
+
+        assertEquals("com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService:sayHello(java.lang.String,int)", resourceName);
+    }
+}
diff --git a/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboConsumerFilterTest.java b/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboConsumerFilterTest.java
new file mode 100644 (file)
index 0000000..e737fd1
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * 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.dubbo;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+import java.util.Set;
+
+import com.alibaba.csp.sentinel.BaseTest;
+import com.alibaba.csp.sentinel.Constants;
+import com.alibaba.csp.sentinel.Entry;
+import com.alibaba.csp.sentinel.EntryType;
+import com.alibaba.csp.sentinel.adapter.dubbo.DubboUtils;
+import com.alibaba.csp.sentinel.adapter.dubbo.SentinelDubboConsumerFilter;
+import com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService;
+import com.alibaba.csp.sentinel.context.Context;
+import com.alibaba.csp.sentinel.context.ContextUtil;
+import com.alibaba.csp.sentinel.node.ClusterNode;
+import com.alibaba.csp.sentinel.node.DefaultNode;
+import com.alibaba.csp.sentinel.node.Node;
+import com.alibaba.csp.sentinel.node.StatisticNode;
+import com.alibaba.csp.sentinel.slotchain.ResourceWrapper;
+
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Result;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * @author cdfive
+ */
+public class SentinelDubboConsumerFilterTest extends BaseTest {
+
+    private SentinelDubboConsumerFilter filter = new SentinelDubboConsumerFilter();
+
+    @Before
+    public void setUp() {
+        cleanUpAll();
+    }
+
+    @After
+    public void cleanUp() {
+        cleanUpAll();
+    }
+
+    @Test
+    public void testInvoke() {
+        final Invoker invoker = mock(Invoker.class);
+        when(invoker.getInterface()).thenReturn(DemoService.class);
+
+        final Invocation invocation = mock(Invocation.class);
+        Method method = DemoService.class.getMethods()[0];
+        when(invocation.getMethodName()).thenReturn(method.getName());
+        when(invocation.getParameterTypes()).thenReturn(method.getParameterTypes());
+
+        final Result result = mock(Result.class);
+        when(result.hasException()).thenReturn(false);
+        when(invoker.invoke(invocation)).thenAnswer(invocationOnMock -> {
+            verifyInvocationStructure(invoker, invocation);
+            return result;
+        });
+
+        filter.invoke(invoker, invocation);
+        verify(invoker).invoke(invocation);
+
+        Context context = ContextUtil.getContext();
+        assertNull(context);
+    }
+
+    /**
+     * Simply verify invocation structure in memory:
+     * EntranceNode(defaultContextName)
+     * --InterfaceNode(interfaceName)
+     * ----MethodNode(resourceName)
+     */
+    private void verifyInvocationStructure(Invoker invoker, Invocation invocation) {
+        Context context = ContextUtil.getContext();
+        assertNotNull(context);
+
+        // As not call ContextUtil.enter(resourceName, application) in SentinelDubboConsumerFilter, use default context
+        // In actual project, a consumer is usually also a provider, the context will be created by SentinelDubboProviderFilter
+        // If consumer is on the top of Dubbo RPC invocation chain, use default context
+        String resourceName = DubboUtils.getResourceName(invoker, invocation);
+        assertEquals(Constants.CONTEXT_DEFAULT_NAME, context.getName());
+        assertEquals("", context.getOrigin());
+
+        DefaultNode entranceNode = context.getEntranceNode();
+        ResourceWrapper entranceResource = entranceNode.getId();
+        assertEquals(Constants.CONTEXT_DEFAULT_NAME, entranceResource.getName());
+        assertSame(EntryType.IN, entranceResource.getType());
+
+        // As SphU.entry(interfaceName, EntryType.OUT);
+        Set<Node> childList = entranceNode.getChildList();
+        assertEquals(1, childList.size());
+        DefaultNode interfaceNode = (DefaultNode) childList.iterator().next();
+        ResourceWrapper interfaceResource = interfaceNode.getId();
+        assertEquals(DemoService.class.getName(), interfaceResource.getName());
+        assertSame(EntryType.OUT, interfaceResource.getType());
+
+        // As SphU.entry(resourceName, EntryType.OUT);
+        childList = interfaceNode.getChildList();
+        assertEquals(1, childList.size());
+        DefaultNode methodNode = (DefaultNode) childList.iterator().next();
+        ResourceWrapper methodResource = methodNode.getId();
+        assertEquals(resourceName, methodResource.getName());
+        assertSame(EntryType.OUT, methodResource.getType());
+
+        // Verify curEntry
+        Entry curEntry = context.getCurEntry();
+        assertSame(methodNode, curEntry.getCurNode());
+        assertSame(interfaceNode, curEntry.getLastNode());
+        assertNull(curEntry.getOriginNode());// As context origin is not "", no originNode should be created in curEntry
+
+        // Verify clusterNode
+        ClusterNode methodClusterNode = methodNode.getClusterNode();
+        ClusterNode interfaceClusterNode = interfaceNode.getClusterNode();
+        assertNotSame(methodClusterNode, interfaceClusterNode);// Different resource->Different ProcessorSlot->Different ClusterNode
+
+        // As context origin is "", the StatisticNode should not be created in originCountMap of ClusterNode
+        Map<String, StatisticNode> methodOriginCountMap = methodClusterNode.getOriginCountMap();
+        assertEquals(0, methodOriginCountMap.size());
+
+        Map<String, StatisticNode> interfaceOriginCountMap = interfaceClusterNode.getOriginCountMap();
+        assertEquals(0, interfaceOriginCountMap.size());
+    }
+}
diff --git a/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboProviderFilterTest.java b/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboProviderFilterTest.java
new file mode 100644 (file)
index 0000000..af858b1
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * 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.dubbo;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+import java.util.Set;
+
+import com.alibaba.csp.sentinel.BaseTest;
+import com.alibaba.csp.sentinel.Entry;
+import com.alibaba.csp.sentinel.EntryType;
+import com.alibaba.csp.sentinel.adapter.dubbo.DubboUtils;
+import com.alibaba.csp.sentinel.adapter.dubbo.SentinelDubboProviderFilter;
+import com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService;
+import com.alibaba.csp.sentinel.context.Context;
+import com.alibaba.csp.sentinel.context.ContextUtil;
+import com.alibaba.csp.sentinel.node.ClusterNode;
+import com.alibaba.csp.sentinel.node.DefaultNode;
+import com.alibaba.csp.sentinel.node.Node;
+import com.alibaba.csp.sentinel.node.StatisticNode;
+import com.alibaba.csp.sentinel.slotchain.ResourceWrapper;
+
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Result;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * @author cdfive
+ */
+public class SentinelDubboProviderFilterTest extends BaseTest {
+
+    private SentinelDubboProviderFilter filter = new SentinelDubboProviderFilter();
+
+    @Before
+    public void setUp() {
+        cleanUpAll();
+    }
+
+    @After
+    public void cleanUp() {
+        cleanUpAll();
+    }
+
+    @Test
+    public void testInvoke() {
+        final String originApplication = "consumerA";
+
+        final Invoker invoker = mock(Invoker.class);
+        when(invoker.getInterface()).thenReturn(DemoService.class);
+
+        final Invocation invocation = mock(Invocation.class);
+        Method method = DemoService.class.getMethods()[0];
+        when(invocation.getMethodName()).thenReturn(method.getName());
+        when(invocation.getParameterTypes()).thenReturn(method.getParameterTypes());
+        when(invocation.getAttachment(DubboUtils.SENTINEL_DUBBO_APPLICATION_KEY, ""))
+            .thenReturn(originApplication);
+
+        final Result result = mock(Result.class);
+        when(result.hasException()).thenReturn(false);
+        when(invoker.invoke(invocation)).thenAnswer(invocationOnMock -> {
+            verifyInvocationStructure(originApplication, invoker, invocation);
+            return result;
+        });
+
+        filter.invoke(invoker, invocation);
+        verify(invoker).invoke(invocation);
+
+        Context context = ContextUtil.getContext();
+        assertNull(context);
+    }
+
+    /**
+     * Simply verify invocation structure in memory:
+     * EntranceNode(resourceName)
+     * --InterfaceNode(interfaceName)
+     * ----MethodNode(resourceName)
+     */
+    private void verifyInvocationStructure(String originApplication, Invoker invoker, Invocation invocation) {
+        Context context = ContextUtil.getContext();
+        assertNotNull(context);
+
+        // As ContextUtil.enter(resourceName, application) in SentinelDubboProviderFilter
+        String resourceName = DubboUtils.getResourceName(invoker, invocation);
+        assertEquals(resourceName, context.getName());
+        assertEquals(originApplication, context.getOrigin());
+
+        DefaultNode entranceNode = context.getEntranceNode();
+        ResourceWrapper entranceResource = entranceNode.getId();
+        assertEquals(resourceName, entranceResource.getName());
+        assertSame(EntryType.IN, entranceResource.getType());
+
+        // As SphU.entry(interfaceName, EntryType.IN);
+        Set<Node> childList = entranceNode.getChildList();
+        assertEquals(1, childList.size());
+        DefaultNode interfaceNode = (DefaultNode) childList.iterator().next();
+        ResourceWrapper interfaceResource = interfaceNode.getId();
+        assertEquals(DemoService.class.getName(), interfaceResource.getName());
+        assertSame(EntryType.IN, interfaceResource.getType());
+
+        // As SphU.entry(resourceName, EntryType.IN, 1, invocation.getArguments());
+        childList = interfaceNode.getChildList();
+        assertEquals(1, childList.size());
+        DefaultNode methodNode = (DefaultNode) childList.iterator().next();
+        ResourceWrapper methodResource = methodNode.getId();
+        assertEquals(resourceName, methodResource.getName());
+        assertSame(EntryType.IN, methodResource.getType());
+
+        // Verify curEntry
+        Entry curEntry = context.getCurEntry();
+        assertSame(methodNode, curEntry.getCurNode());
+        assertSame(interfaceNode, curEntry.getLastNode());
+        assertNotNull(curEntry.getOriginNode());// As context origin is not "", originNode should be created
+
+        // Verify clusterNode
+        ClusterNode methodClusterNode = methodNode.getClusterNode();
+        ClusterNode interfaceClusterNode = interfaceNode.getClusterNode();
+        assertNotSame(methodClusterNode, interfaceClusterNode);// Different resource->Different ProcessorSlot->Different ClusterNode
+
+        // As context origin is not "", the StatisticNode should be created in originCountMap of ClusterNode
+        Map<String, StatisticNode> methodOriginCountMap = methodClusterNode.getOriginCountMap();
+        assertEquals(1, methodOriginCountMap.size());
+        assertTrue(methodOriginCountMap.containsKey(originApplication));
+
+        Map<String, StatisticNode> interfaceOriginCountMap = interfaceClusterNode.getOriginCountMap();
+        assertEquals(1, interfaceOriginCountMap.size());
+        assertTrue(interfaceOriginCountMap.containsKey(originApplication));
+    }
+}
diff --git a/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DubboFallbackRegistryTest.java b/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DubboFallbackRegistryTest.java
new file mode 100644 (file)
index 0000000..bc06ebf
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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.dubbo.fallback;
+
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;
+import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
+
+import org.apache.dubbo.rpc.Result;
+import org.apache.dubbo.rpc.RpcResult;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author Eric Zhao
+ */
+public class DubboFallbackRegistryTest {
+
+    @Test(expected = SentinelRpcException.class)
+    public void testDefaultFallback() {
+        // Test for default.
+        BlockException ex = new FlowException("xxx");
+        DubboFallbackRegistry.getConsumerFallback()
+            .handle(null, null, ex);
+    }
+
+    @Test
+    public void testCustomFallback() {
+        BlockException ex = new FlowException("xxx");
+        DubboFallbackRegistry.setConsumerFallback(
+            (invoker, invocation, e) -> new RpcResult("Error: " + e.getClass().getName()));
+        Result result = DubboFallbackRegistry.getConsumerFallback()
+            .handle(null, null, ex);
+        Assert.assertFalse("The invocation should not fail", result.hasException());
+        Assert.assertEquals("Error: " + ex.getClass().getName(), result.getValue());
+    }
+}
diff --git a/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/provider/DemoService.java b/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/provider/DemoService.java
new file mode 100644 (file)
index 0000000..2a024cc
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * 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.dubbo.provider;
+
+/**
+ * @author leyou
+ */
+public interface DemoService {
+    String sayHello(String name, int n);
+}
diff --git a/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/provider/DemoServiceImpl.java b/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/provider/DemoServiceImpl.java
deleted file mode 100755 (executable)
index db566e7..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.alibaba.csp.sentinel.adapter.dubbo.provider;
-
-import com.alibaba.csp.sentinel.adapter.dubbo.DemoService;
-
-/**
- * @author leyou
- */
-public class DemoServiceImpl implements DemoService {
-    public String sayHello(String name, int n) {
-        return "Hello " + name + ", " + n;
-    }
-}
diff --git a/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/provider/impl/DemoServiceImpl.java b/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/provider/impl/DemoServiceImpl.java
new file mode 100644 (file)
index 0000000..f804c2c
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * 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.dubbo.provider.impl;
+
+import com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService;
+
+/**
+ * @author leyou
+ */
+public class DemoServiceImpl implements DemoService {
+    public String sayHello(String name, int n) {
+        return "Hello " + name + ", " + n;
+    }
+}
index ae0a89ddb5a041977e311fa4ca6c5a42ecdc4407..b129cc9d2ba6a2ec8040ee9c88eac49f5a9f6b38 100755 (executable)
     <dubbo:application name="demo-consumer"/>
     <dubbo:registry address="multicast://224.5.6.7:1234"/>
     <dubbo:protocol name="dubbo" port="20880"/>
-    <dubbo:service interface="com.alibaba.csp.sentinel.adapter.dubbo.DemoService" ref="demoServiceImp" />
-    <bean id="demoServiceImp" class="com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoServiceImpl"/>
+    <dubbo:service interface="com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService" ref="demoServiceImp" />
+    <bean id="demoServiceImp" class="com.alibaba.csp.sentinel.adapter.dubbo.provider.impl.DemoServiceImpl"/>
 
-    <dubbo:reference id="demoService" interface="com.alibaba.csp.sentinel.adapter.dubbo.DemoService"/>
-
-    <dubbo:consumer filter="sentinel.dubbo.consumer.filter" />
+    <dubbo:reference id="demoService" interface="com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService"/>
 
 </beans>
\ No newline at end of file
index 0990c39fd571d611cc9bb44ea96965c786710e0b..bc4a8fb9394272a5c858f12aadf4565d870eb6f3 100755 (executable)
     <dubbo:application name="demo-provider"/>
     <dubbo:registry address="multicast://224.5.6.7:1234"/>
     <dubbo:protocol name="dubbo" port="20880"/>
-    <dubbo:service interface="com.alibaba.csp.sentinel.adapter.dubbo.DemoService" ref="demoServiceImp" />
-    <bean id="demoServiceImp" class="com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoServiceImpl"/>
+    <dubbo:service interface="com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService" ref="demoServiceImp" />
+    <bean id="demoServiceImp" class="com.alibaba.csp.sentinel.adapter.dubbo.provider.impl.DemoServiceImpl"/>
 
-    <dubbo:reference id="demoService" interface="com.alibaba.csp.sentinel.adapter.dubbo.DemoService"/>
-
-    <dubbo:provider filter="sentinel.dubbo.provider.filter" />
+    <dubbo:reference id="demoService" interface="com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService"/>
 
 </beans>
\ No newline at end of file