@@ -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(); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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<String, String>()); | |||
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!"); | |||
} | |||
} |
@@ -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<Object>() { | |||
@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<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()); | |||
} | |||
} |
@@ -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<Object>() { | |||
@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<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)); | |||
} | |||
} |
@@ -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 |
@@ -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 |
@@ -10,9 +10,9 @@ | |||
<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:reference id="demoService" interface="com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService"/> | |||
</beans> |
@@ -10,9 +10,9 @@ | |||
<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:reference id="demoService" interface="com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService"/> | |||
</beans> |