diff --git a/sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/BaseTest.java b/sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/BaseTest.java new file mode 100644 index 00000000..5c44496a --- /dev/null +++ b/sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/BaseTest.java @@ -0,0 +1,24 @@ +package com.alibaba.csp.sentinel; + +import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot; +import com.alibaba.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/sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/AbstractDubboFilterTest.java b/sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/AbstractDubboFilterTest.java new file mode 100644 index 00000000..69b95c6d --- /dev/null +++ b/sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/AbstractDubboFilterTest.java @@ -0,0 +1,41 @@ +package com.alibaba.csp.sentinel.adapter.dubbo; + +import com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService; +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.junit.Test; + +import java.lang.reflect.Method; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +/** + * @author cdfive + */ +public class AbstractDubboFilterTest { + + private AbstractDubboFilter filter = new AbstractDubboFilter() { + @Override + public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { + return null; + } + }; + + @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 = filter.getResourceName(invoker, invocation); + + assertEquals("com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService:sayHello(java.lang.String,int)", resourceName); + } +} diff --git a/sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboAppContextFilterTest.java b/sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboAppContextFilterTest.java new file mode 100644 index 00000000..251eef19 --- /dev/null +++ b/sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboAppContextFilterTest.java @@ -0,0 +1,59 @@ +package com.alibaba.csp.sentinel.adapter.dubbo; + +import com.alibaba.csp.sentinel.BaseTest; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcContext; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +/** + * @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.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.DUBBO_APPLICATION_KEY); + assertNull(application); + } +} diff --git a/sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboUtilsTest.java b/sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboUtilsTest.java new file mode 100644 index 00000000..a6b33a6b --- /dev/null +++ b/sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboUtilsTest.java @@ -0,0 +1,39 @@ +package com.alibaba.csp.sentinel.adapter.dubbo; + +import com.alibaba.dubbo.rpc.Invocation; +import org.junit.Test; + +import java.util.HashMap; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.*; + +/** + * @author cdfive + */ +public class DubboUtilsTest { + + @Test + public void testGetApplication() { + Invocation invocation = mock(Invocation.class); + when(invocation.getAttachments()).thenReturn(new HashMap()); + when(invocation.getAttachment(DubboUtils.DUBBO_APPLICATION_KEY, "")).thenReturn("consumerA"); + + String application = DubboUtils.getApplication(invocation, ""); + verify(invocation).getAttachment(DubboUtils.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.DUBBO_APPLICATION_KEY, "")).thenReturn("consumerA"); + + DubboUtils.getApplication(invocation, ""); + + fail("No attachments in invocation, IllegalArgumentException should be thrown!"); + } +} diff --git a/sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboConsumerFilterTest.java b/sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboConsumerFilterTest.java new file mode 100644 index 00000000..a71b0d00 --- /dev/null +++ b/sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboConsumerFilterTest.java @@ -0,0 +1,131 @@ +package com.alibaba.csp.sentinel.adapter.dubbo; + +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.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 com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.lang.reflect.Method; +import java.util.Map; +import java.util.Set; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +/** + * @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(new Answer() { + @Override + public Object answer(InvocationOnMock invocationOnMock) throws Throwable { + 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 = filter.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 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 methodOriginCountMap = methodClusterNode.getOriginCountMap(); + assertEquals(0, methodOriginCountMap.size()); + + Map interfaceOriginCountMap = interfaceClusterNode.getOriginCountMap(); + assertEquals(0, interfaceOriginCountMap.size()); + } +} diff --git a/sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboProviderFilterTest.java b/sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboProviderFilterTest.java new file mode 100644 index 00000000..809a5c71 --- /dev/null +++ b/sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboProviderFilterTest.java @@ -0,0 +1,133 @@ +package com.alibaba.csp.sentinel.adapter.dubbo; + +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.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 com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Result; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.lang.reflect.Method; +import java.util.Map; +import java.util.Set; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +/** + * @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.DUBBO_APPLICATION_KEY, "")).thenReturn(originApplication); + + final Result result = mock(Result.class); + when(result.hasException()).thenReturn(false); + when(invoker.invoke(invocation)).thenAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocationOnMock) throws Throwable { + 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 = filter.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 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 methodOriginCountMap = methodClusterNode.getOriginCountMap(); + assertEquals(1, methodOriginCountMap.size()); + assertTrue(methodOriginCountMap.containsKey(originApplication)); + + Map interfaceOriginCountMap = interfaceClusterNode.getOriginCountMap(); + assertEquals(1, interfaceOriginCountMap.size()); + assertTrue(interfaceOriginCountMap.containsKey(originApplication)); + } +} diff --git a/sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DemoService.java b/sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/provider/DemoService.java old mode 100755 new mode 100644 similarity index 92% rename from sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DemoService.java rename to sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/provider/DemoService.java index 882de9ef..2a024cc9 --- a/sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DemoService.java +++ b/sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/provider/DemoService.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.alibaba.csp.sentinel.adapter.dubbo; +package com.alibaba.csp.sentinel.adapter.dubbo.provider; /** * @author leyou diff --git a/sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/provider/DemoServiceImpl.java b/sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/provider/impl/DemoServiceImpl.java old mode 100755 new mode 100644 similarity index 85% rename from sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/provider/DemoServiceImpl.java rename to sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/provider/impl/DemoServiceImpl.java index b5dfd930..f804c2c4 --- a/sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/provider/DemoServiceImpl.java +++ b/sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/provider/impl/DemoServiceImpl.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.alibaba.csp.sentinel.adapter.dubbo.provider; +package com.alibaba.csp.sentinel.adapter.dubbo.provider.impl; -import com.alibaba.csp.sentinel.adapter.dubbo.DemoService; +import com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService; /** * @author leyou diff --git a/sentinel-adapter/sentinel-dubbo-adapter/src/test/resources/spring-dubbo-consumer-filter.xml b/sentinel-adapter/sentinel-dubbo-adapter/src/test/resources/spring-dubbo-consumer-filter.xml index aef82044..b129cc9d 100755 --- a/sentinel-adapter/sentinel-dubbo-adapter/src/test/resources/spring-dubbo-consumer-filter.xml +++ b/sentinel-adapter/sentinel-dubbo-adapter/src/test/resources/spring-dubbo-consumer-filter.xml @@ -10,9 +10,9 @@ - - + + - + \ No newline at end of file diff --git a/sentinel-adapter/sentinel-dubbo-adapter/src/test/resources/spring-dubbo-provider-filter.xml b/sentinel-adapter/sentinel-dubbo-adapter/src/test/resources/spring-dubbo-provider-filter.xml index 95e3eca5..bc4a8fb9 100755 --- a/sentinel-adapter/sentinel-dubbo-adapter/src/test/resources/spring-dubbo-provider-filter.xml +++ b/sentinel-adapter/sentinel-dubbo-adapter/src/test/resources/spring-dubbo-provider-filter.xml @@ -10,9 +10,9 @@ - - + + - + \ No newline at end of file