@@ -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 | * See the License for the specific language governing permissions and | ||||
* limitations under the License. | * limitations under the License. | ||||
*/ | */ | ||||
package com.alibaba.csp.sentinel.adapter.dubbo; | |||||
package com.alibaba.csp.sentinel.adapter.dubbo.provider; | |||||
/** | /** | ||||
* @author leyou | * @author leyou |
@@ -13,9 +13,9 @@ | |||||
* See the License for the specific language governing permissions and | * See the License for the specific language governing permissions and | ||||
* limitations under the License. | * 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 | * @author leyou |
@@ -10,9 +10,9 @@ | |||||
<dubbo:application name="demo-consumer"/> | <dubbo:application name="demo-consumer"/> | ||||
<dubbo:registry address="multicast://224.5.6.7:1234"/> | <dubbo:registry address="multicast://224.5.6.7:1234"/> | ||||
<dubbo:protocol name="dubbo" port="20880"/> | <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> | </beans> |
@@ -10,9 +10,9 @@ | |||||
<dubbo:application name="demo-provider"/> | <dubbo:application name="demo-provider"/> | ||||
<dubbo:registry address="multicast://224.5.6.7:1234"/> | <dubbo:registry address="multicast://224.5.6.7:1234"/> | ||||
<dubbo:protocol name="dubbo" port="20880"/> | <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> | </beans> |