@@ -16,13 +16,9 @@ | |||
package com.alibaba.csp.sentinel.adapter.dubbo; | |||
import com.alibaba.csp.sentinel.Entry; | |||
import com.alibaba.csp.sentinel.Tracer; | |||
import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboConfig; | |||
import com.alibaba.csp.sentinel.context.ContextUtil; | |||
import org.apache.dubbo.common.URL; | |||
import org.apache.dubbo.common.constants.CommonConstants; | |||
import org.apache.dubbo.rpc.*; | |||
import org.apache.dubbo.rpc.Filter; | |||
import org.apache.dubbo.rpc.Invocation; | |||
import org.apache.dubbo.rpc.Invoker; | |||
/** | |||
* Base Class of the {@link SentinelDubboProviderFilter} and {@link SentinelDubboConsumerFilter}. | |||
@@ -30,52 +26,25 @@ import org.apache.dubbo.rpc.*; | |||
* @author Zechao Zheng | |||
*/ | |||
public abstract class BaseSentinelDubboFilter extends ListenableFilter { | |||
public BaseSentinelDubboFilter() { | |||
this.listener = new SentinelDubboListener(); | |||
} | |||
public abstract class BaseSentinelDubboFilter implements Filter { | |||
static class SentinelDubboListener implements Listener { | |||
public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) { | |||
onSuccess(appResponse, invoker); | |||
} | |||
/** | |||
* Get method name of dubbo rpc | |||
* | |||
* @param invoker | |||
* @param invocation | |||
* @return | |||
*/ | |||
abstract String getMethodName(Invoker invoker, Invocation invocation); | |||
//for compatible dubbo 2.7.5 rename onResponse to onMessage | |||
public void onMessage(Result appResponse, Invoker<?> invoker, Invocation invocation) { | |||
onSuccess(appResponse, invoker); | |||
} | |||
/** | |||
* Get interface name of dubbo rpc | |||
* | |||
* @param invoker | |||
* @return | |||
*/ | |||
abstract String getInterfaceName(Invoker invoker); | |||
private void onSuccess(Result appResponse, Invoker<?> invoker) { | |||
if (DubboConfig.getDubboBizExceptionTraceEnabled()) { | |||
traceAndExit(appResponse.getException(), invoker.getUrl()); | |||
} else { | |||
traceAndExit(null, invoker.getUrl()); | |||
} | |||
} | |||
@Override | |||
public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) { | |||
traceAndExit(t, invoker.getUrl()); | |||
} | |||
} | |||
static void traceAndExit(Throwable throwable, URL url) { | |||
Entry interfaceEntry = (Entry) RpcContext.getContext().get(DubboUtils.DUBBO_INTERFACE_ENTRY_KEY); | |||
Entry methodEntry = (Entry) RpcContext.getContext().get(DubboUtils.DUBBO_METHOD_ENTRY_KEY); | |||
if (methodEntry != null) { | |||
Tracer.traceEntry(throwable, methodEntry); | |||
methodEntry.exit(); | |||
RpcContext.getContext().remove(DubboUtils.DUBBO_METHOD_ENTRY_KEY); | |||
} | |||
if (interfaceEntry != null) { | |||
Tracer.traceEntry(throwable, interfaceEntry); | |||
interfaceEntry.exit(); | |||
RpcContext.getContext().remove(DubboUtils.DUBBO_INTERFACE_ENTRY_KEY); | |||
} | |||
if (CommonConstants.PROVIDER_SIDE.equals(url.getParameter(CommonConstants.SIDE_KEY))) { | |||
ContextUtil.exit(); | |||
} | |||
} | |||
} |
@@ -26,8 +26,6 @@ import org.apache.dubbo.rpc.Invoker; | |||
public final class DubboUtils { | |||
public static final String SENTINEL_DUBBO_APPLICATION_KEY = "dubboApplication"; | |||
public static final String DUBBO_METHOD_ENTRY_KEY = "dubboMethodEntry"; | |||
public static final String DUBBO_INTERFACE_ENTRY_KEY = "dubboInterfaceEntry"; | |||
public static String getApplication(Invocation invocation, String defaultValue) { | |||
if (invocation == null || invocation.getAttachments() == null) { | |||
@@ -69,6 +67,13 @@ public final class DubboUtils { | |||
return getResourceName(invoker, invocation, DubboConfig.getDubboInterfaceGroupAndVersionEnabled()); | |||
} | |||
} | |||
public static String getInterfaceName(Invoker invoker) { | |||
return DubboConfig.getDubboInterfaceGroupAndVersionEnabled() ? invoker.getUrl().getColonSeparatedKey() | |||
: invoker.getInterface().getName(); | |||
} | |||
private DubboUtils() { | |||
} | |||
} |
@@ -19,6 +19,7 @@ import com.alibaba.csp.sentinel.Entry; | |||
import com.alibaba.csp.sentinel.EntryType; | |||
import com.alibaba.csp.sentinel.ResourceTypeConstants; | |||
import com.alibaba.csp.sentinel.SphU; | |||
import com.alibaba.csp.sentinel.Tracer; | |||
import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboConfig; | |||
import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallbackRegistry; | |||
import com.alibaba.csp.sentinel.log.RecordLog; | |||
@@ -28,10 +29,12 @@ import org.apache.dubbo.rpc.Invocation; | |||
import org.apache.dubbo.rpc.InvokeMode; | |||
import org.apache.dubbo.rpc.Invoker; | |||
import org.apache.dubbo.rpc.Result; | |||
import org.apache.dubbo.rpc.RpcContext; | |||
import org.apache.dubbo.rpc.RpcException; | |||
import org.apache.dubbo.rpc.support.RpcUtils; | |||
import java.util.LinkedList; | |||
import java.util.function.BiConsumer; | |||
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER; | |||
/** | |||
@@ -52,33 +55,85 @@ public class SentinelDubboConsumerFilter extends BaseSentinelDubboFilter { | |||
RecordLog.info("Sentinel Apache Dubbo consumer filter initialized"); | |||
} | |||
@Override | |||
String getMethodName(Invoker invoker, Invocation invocation) { | |||
return DubboUtils.getResourceName(invoker, invocation, DubboConfig.getDubboConsumerPrefix()); | |||
} | |||
@Override | |||
String getInterfaceName(Invoker invoker) { | |||
return DubboUtils.getInterfaceName(invoker); | |||
} | |||
@Override | |||
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { | |||
InvokeMode invokeMode = RpcUtils.getInvokeMode(invoker.getUrl(), invocation); | |||
if (InvokeMode.SYNC == invokeMode) { | |||
return syncInvoke(invoker, invocation); | |||
} else { | |||
return asyncInvoke(invoker, invocation); | |||
} | |||
} | |||
private Result syncInvoke(Invoker<?> invoker, Invocation invocation) { | |||
Entry interfaceEntry = null; | |||
Entry methodEntry = null; | |||
RpcContext rpcContext = RpcContext.getContext(); | |||
String methodResourceName = getMethodName(invoker, invocation); | |||
String interfaceResourceName = getInterfaceName(invoker); | |||
try { | |||
String methodResourceName = DubboUtils.getResourceName(invoker, invocation, DubboConfig.getDubboConsumerPrefix()); | |||
String interfaceResourceName = DubboConfig.getDubboInterfaceGroupAndVersionEnabled() ? invoker.getUrl().getColonSeparatedKey() | |||
: invoker.getInterface().getName(); | |||
InvokeMode invokeMode = RpcUtils.getInvokeMode(invoker.getUrl(), invocation); | |||
if (InvokeMode.SYNC == invokeMode) { | |||
interfaceEntry = SphU.entry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT); | |||
rpcContext.set(DubboUtils.DUBBO_INTERFACE_ENTRY_KEY, interfaceEntry); | |||
methodEntry = SphU.entry(methodResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT, invocation.getArguments()); | |||
} else { | |||
// should generate the AsyncEntry when the invoke model in future or async | |||
interfaceEntry = SphU.asyncEntry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT); | |||
rpcContext.set(DubboUtils.DUBBO_INTERFACE_ENTRY_KEY, interfaceEntry); | |||
methodEntry = SphU.asyncEntry(methodResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT, 1, invocation.getArguments()); | |||
interfaceEntry = SphU.entry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT); | |||
methodEntry = SphU.entry(methodResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT, invocation.getArguments()); | |||
Result result = invoker.invoke(invocation); | |||
if (result.hasException()) { | |||
Tracer.traceEntry(result.getException(), interfaceEntry); | |||
Tracer.traceEntry(result.getException(), methodEntry); | |||
} | |||
rpcContext.set(DubboUtils.DUBBO_METHOD_ENTRY_KEY, methodEntry); | |||
return invoker.invoke(invocation); | |||
return result; | |||
} catch (BlockException e) { | |||
return DubboFallbackRegistry.getConsumerFallback().handle(invoker, invocation, e); | |||
} catch (RpcException e) { | |||
Tracer.traceEntry(e, interfaceEntry); | |||
Tracer.traceEntry(e, methodEntry); | |||
throw e; | |||
} finally { | |||
if (methodEntry != null) { | |||
methodEntry.exit(); | |||
} | |||
if (interfaceEntry != null) { | |||
interfaceEntry.exit(); | |||
} | |||
} | |||
} | |||
private Result asyncInvoke(Invoker<?> invoker, Invocation invocation) { | |||
LinkedList<Entry> queue = new LinkedList<>(); | |||
String methodResourceName = getMethodName(invoker, invocation); | |||
String interfaceResourceName = getInterfaceName(invoker); | |||
try { | |||
queue.push(SphU.asyncEntry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT)); | |||
queue.push(SphU.asyncEntry(methodResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT, 1, invocation.getArguments())); | |||
Result result = invoker.invoke(invocation); | |||
result.whenCompleteWithContext(new BiConsumer<Result, Throwable>() { | |||
@Override | |||
public void accept(Result result, Throwable throwable) { | |||
while (!queue.isEmpty()) { | |||
Entry entry = queue.pop(); | |||
Tracer.traceEntry(result.getException(), entry); | |||
entry.exit(); | |||
} | |||
} | |||
}); | |||
return result; | |||
} catch (BlockException e) { | |||
while (!queue.isEmpty()) { | |||
queue.pop().exit(); | |||
} | |||
return DubboFallbackRegistry.getConsumerFallback().handle(invoker, invocation, e); | |||
} | |||
} | |||
} | |||
@@ -19,16 +19,17 @@ import com.alibaba.csp.sentinel.Entry; | |||
import com.alibaba.csp.sentinel.EntryType; | |||
import com.alibaba.csp.sentinel.ResourceTypeConstants; | |||
import com.alibaba.csp.sentinel.SphU; | |||
import com.alibaba.csp.sentinel.Tracer; | |||
import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboConfig; | |||
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 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; | |||
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER; | |||
@@ -52,27 +53,50 @@ public class SentinelDubboProviderFilter extends BaseSentinelDubboFilter { | |||
RecordLog.info("Sentinel Apache Dubbo provider filter initialized"); | |||
} | |||
@Override | |||
String getMethodName(Invoker invoker, Invocation invocation) { | |||
return DubboUtils.getResourceName(invoker, invocation, DubboConfig.getDubboProviderPrefix()); | |||
} | |||
@Override | |||
String getInterfaceName(Invoker invoker) { | |||
return DubboUtils.getInterfaceName(invoker); | |||
} | |||
@Override | |||
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { | |||
// Get origin caller. | |||
String application = DubboUtils.getApplication(invocation, ""); | |||
RpcContext rpcContext = RpcContext.getContext(); | |||
Entry interfaceEntry = null; | |||
Entry methodEntry = null; | |||
String methodResourceName = getMethodName(invoker, invocation); | |||
String interfaceResourceName = getInterfaceName(invoker); | |||
try { | |||
String methodResourceName = DubboUtils.getResourceName(invoker, invocation, DubboConfig.getDubboProviderPrefix()); | |||
String interfaceResourceName = DubboConfig.getDubboInterfaceGroupAndVersionEnabled() ? invoker.getUrl().getColonSeparatedKey() | |||
: 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(methodResourceName, application); | |||
interfaceEntry = SphU.entry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.IN); | |||
rpcContext.set(DubboUtils.DUBBO_INTERFACE_ENTRY_KEY, interfaceEntry); | |||
methodEntry = SphU.entry(methodResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.IN, invocation.getArguments()); | |||
rpcContext.set(DubboUtils.DUBBO_METHOD_ENTRY_KEY, methodEntry); | |||
return invoker.invoke(invocation); | |||
Result result = invoker.invoke(invocation); | |||
if (result.hasException()) { | |||
Tracer.traceEntry(result.getException(), interfaceEntry); | |||
Tracer.traceEntry(result.getException(), methodEntry); | |||
} | |||
return result; | |||
} catch (BlockException e) { | |||
return DubboFallbackRegistry.getProviderFallback().handle(invoker, invocation, e); | |||
} catch (RpcException e) { | |||
Tracer.traceEntry(e, interfaceEntry); | |||
Tracer.traceEntry(e, methodEntry); | |||
throw e; | |||
} finally { | |||
if (methodEntry != null) { | |||
methodEntry.exit(1, invocation.getArguments()); | |||
} | |||
if (interfaceEntry != null) { | |||
interfaceEntry.exit(); | |||
} | |||
ContextUtil.exit(); | |||
} | |||
} | |||
@@ -16,25 +16,19 @@ | |||
package com.alibaba.csp.sentinel; | |||
import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboConfig; | |||
import com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService; | |||
import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DefaultDubboFallback; | |||
import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallbackRegistry; | |||
import com.alibaba.csp.sentinel.config.SentinelConfig; | |||
import com.alibaba.csp.sentinel.context.ContextUtil; | |||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager; | |||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; | |||
import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot; | |||
import org.apache.dubbo.common.URL; | |||
import org.apache.dubbo.common.constants.CommonConstants; | |||
import org.apache.dubbo.rpc.Invocation; | |||
import org.apache.dubbo.rpc.Invoker; | |||
import org.apache.dubbo.rpc.RpcContext; | |||
import java.lang.reflect.InvocationTargetException; | |||
import java.lang.reflect.Method; | |||
import java.util.ArrayList; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
/** | |||
* Base test class, provide common methods for subClass | |||
* The package is same as CtSph, to call CtSph.resetChainMap() method for test | |||
@@ -42,46 +36,41 @@ import static org.mockito.Mockito.when; | |||
* Note: Only for test. DO NOT USE IN PRODUCTION! | |||
* | |||
* @author cdfive | |||
* @author lianglin | |||
*/ | |||
public class BaseTest { | |||
protected Invoker invoker; | |||
protected Invocation invocation; | |||
public void constructInvokerAndInvocation() { | |||
invoker = mock(Invoker.class); | |||
URL url = URL.valueOf("dubbo://127.0.0.1:2181") | |||
.addParameter(CommonConstants.VERSION_KEY, "1.0.0") | |||
.addParameter(CommonConstants.GROUP_KEY, "grp1") | |||
.addParameter(CommonConstants.INTERFACE_KEY, DemoService.class.getName()); | |||
when(invoker.getUrl()).thenReturn(url); | |||
when(invoker.getInterface()).thenReturn(DemoService.class); | |||
invocation = mock(Invocation.class); | |||
Method method = DemoService.class.getMethods()[0]; | |||
when(invocation.getMethodName()).thenReturn(method.getName()); | |||
when(invocation.getParameterTypes()).thenReturn(method.getParameterTypes()); | |||
} | |||
/** | |||
* Clean up resources for context, clusterNodeMap, processorSlotChainMap | |||
*/ | |||
protected static void cleanUpAll() { | |||
public void cleanUpAll() { | |||
try { | |||
RpcContext.removeContext(); | |||
ClusterBuilderSlot.getClusterNodeMap().clear(); | |||
CtSph.resetChainMap(); | |||
Method method = ContextUtil.class.getDeclaredMethod("resetContextMap"); | |||
method.setAccessible(true); | |||
method.invoke(null, null); | |||
ContextUtil.exit(); | |||
SentinelConfig.setConfig(DubboConfig.DUBBO_INTERFACE_GROUP_VERSION_ENABLED, "true"); | |||
FlowRuleManager.loadRules(new ArrayList<>()); | |||
DegradeRuleManager.loadRules(new ArrayList<>()); | |||
clearDubboContext(); | |||
cleanUpCstContext(); | |||
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
private void cleanUpCstContext() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { | |||
ClusterBuilderSlot.getClusterNodeMap().clear(); | |||
CtSph.resetChainMap(); | |||
Method method = ContextUtil.class.getDeclaredMethod("resetContextMap"); | |||
method.setAccessible(true); | |||
method.invoke(null, null); | |||
ContextUtil.exit(); | |||
FlowRuleManager.loadRules(new ArrayList<>()); | |||
DegradeRuleManager.loadRules(new ArrayList<>()); | |||
} | |||
private void clearDubboContext() { | |||
SentinelConfig.setConfig("csp.sentinel.dubbo.resource.use.prefix", "false"); | |||
SentinelConfig.setConfig(DubboConfig.DUBBO_PROVIDER_PREFIX, ""); | |||
SentinelConfig.setConfig(DubboConfig.DUBBO_CONSUMER_PREFIX, ""); | |||
SentinelConfig.setConfig(DubboConfig.DUBBO_INTERFACE_GROUP_VERSION_ENABLED, "false"); | |||
DubboFallbackRegistry.setConsumerFallback(new DefaultDubboFallback()); | |||
RpcContext.removeContext(); | |||
} | |||
} |
@@ -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; | |||
import com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService; | |||
import org.apache.dubbo.common.URL; | |||
import org.apache.dubbo.common.constants.CommonConstants; | |||
import org.apache.dubbo.rpc.Invocation; | |||
import org.apache.dubbo.rpc.Invoker; | |||
import java.lang.reflect.Method; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
/** | |||
* @author lianglin | |||
*/ | |||
public class DubboTestUtil { | |||
public static Class<?> DEFAULT_TEST_SERVICE = DemoService.class; | |||
public static Method DEFAULT_TEST_METHOD_ONE = DEFAULT_TEST_SERVICE.getMethods()[0]; | |||
public static Method DEFAULT_TEST_METHOD_TWO = DEFAULT_TEST_SERVICE.getMethods()[1]; | |||
public static Invoker getMockInvoker(URL url, Class<?> cls) { | |||
Invoker invoker = mock(Invoker.class); | |||
when(invoker.getUrl()).thenReturn(url); | |||
when(invoker.getInterface()).thenReturn(cls); | |||
return invoker; | |||
} | |||
public static Invoker getDefaultMockInvoker() { | |||
return getMockInvoker(getDefaultTestURL(), DEFAULT_TEST_SERVICE); | |||
} | |||
public static Invocation getMockInvocation(Method method) { | |||
Invocation invocation = mock(Invocation.class); | |||
when(invocation.getMethodName()).thenReturn(method.getName()); | |||
when(invocation.getParameterTypes()).thenReturn(method.getParameterTypes()); | |||
return invocation; | |||
} | |||
public static Invocation getDefaultMockInvocationOne() { | |||
Invocation invocation = mock(Invocation.class); | |||
when(invocation.getMethodName()).thenReturn(DEFAULT_TEST_METHOD_ONE.getName()); | |||
when(invocation.getParameterTypes()).thenReturn(DEFAULT_TEST_METHOD_ONE.getParameterTypes()); | |||
return invocation; | |||
} | |||
public static Invocation getDefaultMockInvocationTwo() { | |||
Invocation invocation = mock(Invocation.class); | |||
when(invocation.getMethodName()).thenReturn(DEFAULT_TEST_METHOD_TWO.getName()); | |||
when(invocation.getParameterTypes()).thenReturn(DEFAULT_TEST_METHOD_TWO.getParameterTypes()); | |||
return invocation; | |||
} | |||
public static URL getDefaultTestURL() { | |||
URL url = URL.valueOf("dubbo://127.0.0.1:2181") | |||
.addParameter(CommonConstants.VERSION_KEY, "1.0.0") | |||
.addParameter(CommonConstants.GROUP_KEY, "grp1") | |||
.addParameter(CommonConstants.INTERFACE_KEY, DEFAULT_TEST_SERVICE.getName()); | |||
return url; | |||
} | |||
} |
@@ -29,11 +29,10 @@ import org.junit.Test; | |||
import java.lang.reflect.Method; | |||
import java.util.HashMap; | |||
import static com.alibaba.csp.sentinel.adapter.dubbo.config.DubboConfig.DUBBO_INTERFACE_GROUP_VERSION_ENABLED; | |||
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; | |||
import static org.mockito.Mockito.*; | |||
/** | |||
* @author cdfive | |||
@@ -45,7 +44,7 @@ public class DubboUtilsTest { | |||
SentinelConfig.setConfig("csp.sentinel.dubbo.resource.use.prefix", "true"); | |||
SentinelConfig.setConfig(DubboConfig.DUBBO_PROVIDER_PREFIX, ""); | |||
SentinelConfig.setConfig(DubboConfig.DUBBO_CONSUMER_PREFIX, ""); | |||
SentinelConfig.setConfig(DubboConfig.DUBBO_INTERFACE_GROUP_VERSION_ENABLED, "false"); | |||
SentinelConfig.setConfig(DUBBO_INTERFACE_GROUP_VERSION_ENABLED, "false"); | |||
} | |||
@@ -54,7 +53,7 @@ public class DubboUtilsTest { | |||
SentinelConfig.setConfig("csp.sentinel.dubbo.resource.use.prefix", "false"); | |||
SentinelConfig.setConfig(DubboConfig.DUBBO_PROVIDER_PREFIX, ""); | |||
SentinelConfig.setConfig(DubboConfig.DUBBO_CONSUMER_PREFIX, ""); | |||
SentinelConfig.setConfig(DubboConfig.DUBBO_INTERFACE_GROUP_VERSION_ENABLED, "false"); | |||
SentinelConfig.setConfig(DUBBO_INTERFACE_GROUP_VERSION_ENABLED, "false"); | |||
} | |||
@@ -146,4 +145,23 @@ public class DubboUtilsTest { | |||
assertEquals("my:dubbo:consumer:com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService:sayHello(java.lang.String,int)", resourceName); | |||
} | |||
@Test | |||
public void testGetInterfaceName() { | |||
URL url = URL.valueOf("dubbo://127.0.0.1:2181") | |||
.addParameter(CommonConstants.VERSION_KEY, "1.0.0") | |||
.addParameter(CommonConstants.GROUP_KEY, "grp1") | |||
.addParameter(CommonConstants.INTERFACE_KEY, DemoService.class.getName()); | |||
Invoker invoker = mock(Invoker.class); | |||
when(invoker.getUrl()).thenReturn(url); | |||
when(invoker.getInterface()).thenReturn(DemoService.class); | |||
SentinelConfig.setConfig(DUBBO_INTERFACE_GROUP_VERSION_ENABLED, "false"); | |||
assertEquals("com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService", DubboUtils.getInterfaceName(invoker)); | |||
SentinelConfig.setConfig(DUBBO_INTERFACE_GROUP_VERSION_ENABLED, "true"); | |||
assertEquals("com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService:1.0.0:grp1", DubboUtils.getInterfaceName(invoker)); | |||
} | |||
} |
@@ -16,13 +16,11 @@ | |||
package com.alibaba.csp.sentinel.adapter.dubbo; | |||
import com.alibaba.csp.sentinel.BaseTest; | |||
import com.alibaba.csp.sentinel.DubboTestUtil; | |||
import com.alibaba.csp.sentinel.Entry; | |||
import com.alibaba.csp.sentinel.EntryType; | |||
import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboConfig; | |||
import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DefaultDubboFallback; | |||
import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallback; | |||
import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallbackRegistry; | |||
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; | |||
@@ -36,8 +34,10 @@ import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule; | |||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager; | |||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; | |||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; | |||
import org.apache.dubbo.rpc.AppResponse; | |||
import org.apache.dubbo.rpc.AsyncRpcResult; | |||
import org.apache.dubbo.rpc.Invocation; | |||
import org.apache.dubbo.rpc.InvokeMode; | |||
import org.apache.dubbo.rpc.Invoker; | |||
import org.apache.dubbo.rpc.Result; | |||
import org.apache.dubbo.rpc.RpcContext; | |||
@@ -46,7 +46,6 @@ import org.junit.After; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import java.lang.reflect.Method; | |||
import java.util.ArrayList; | |||
import java.util.LinkedList; | |||
import java.util.List; | |||
@@ -56,105 +55,80 @@ import java.util.Set; | |||
import static com.alibaba.csp.sentinel.slots.block.RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO; | |||
import static org.apache.dubbo.rpc.Constants.ASYNC_KEY; | |||
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; | |||
import static org.junit.Assert.*; | |||
import static org.mockito.Mockito.*; | |||
/** | |||
* @author cdfive | |||
* @author lianglin | |||
*/ | |||
public class SentinelDubboConsumerFilterTest extends BaseTest { | |||
private SentinelDubboConsumerFilter filter = new SentinelDubboConsumerFilter(); | |||
private SentinelDubboConsumerFilter consumerFilter = new SentinelDubboConsumerFilter(); | |||
@Before | |||
public void setUp() { | |||
cleanUpAll(); | |||
initFallback(); | |||
constructInvokerAndInvocation(); | |||
} | |||
@After | |||
public void cleanUp() { | |||
public void destroy() { | |||
cleanUpAll(); | |||
DubboFallbackRegistry.setConsumerFallback(new DefaultDubboFallback()); | |||
} | |||
public void initFlowRule(String resource) { | |||
FlowRule flowRule = new FlowRule(resource); | |||
flowRule.setCount(1); | |||
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS); | |||
List<FlowRule> flowRules = new ArrayList<>(); | |||
flowRules.add(flowRule); | |||
FlowRuleManager.loadRules(flowRules); | |||
} | |||
public void initDegradeRule(String resource) { | |||
DegradeRule degradeRule = new DegradeRule(resource) | |||
.setCount(0.5) | |||
.setGrade(DEGRADE_GRADE_EXCEPTION_RATIO); | |||
List<DegradeRule> degradeRules = new ArrayList<>(); | |||
degradeRules.add(degradeRule); | |||
degradeRule.setTimeWindow(1); | |||
DegradeRuleManager.loadRules(degradeRules); | |||
} | |||
public void initFallback() { | |||
DubboFallbackRegistry.setConsumerFallback(new DubboFallback() { | |||
@Override | |||
public Result handle(Invoker<?> invoker, Invocation invocation, BlockException ex) { | |||
boolean async = RpcUtils.isAsync(invoker.getUrl(), invocation); | |||
Result fallbackResult = null; | |||
fallbackResult = AsyncRpcResult.newDefaultAsyncResult("fallback", invocation); | |||
return fallbackResult; | |||
} | |||
}); | |||
} | |||
@Test | |||
public void testInterfaceLevelFollowControlAsync() throws InterruptedException { | |||
Invoker invoker = DubboTestUtil.getDefaultMockInvoker(); | |||
Invocation invocation = DubboTestUtil.getDefaultMockInvocationOne(); | |||
when(invocation.getAttachment(ASYNC_KEY)).thenReturn(Boolean.TRUE.toString()); | |||
initFlowRule(invoker.getUrl().getColonSeparatedKey()); | |||
Result result1 = responseBack(requestGo(false, invocation)); | |||
initFlowRule(DubboUtils.getInterfaceName(invoker)); | |||
Result result1 = invokeDubboRpc(false, invoker, invocation); | |||
assertEquals("normal", result1.getValue()); | |||
// should fallback because the qps > 1 | |||
Result result2 = responseBack(requestGo(false, invocation)); | |||
Result result2 = invokeDubboRpc(false, invoker, invocation); | |||
assertEquals("fallback", result2.getValue()); | |||
// sleeping 1000 ms to reset qps | |||
Thread.sleep(1000); | |||
Result result3 = responseBack(requestGo(false, invocation)); | |||
Result result3 = invokeDubboRpc(false, invoker, invocation); | |||
assertEquals("normal", result3.getValue()); | |||
verifyInvocationStructureForCallFinish(); | |||
verifyInvocationStructureForCallFinish(invoker, invocation); | |||
} | |||
@Test | |||
public void testDegradeAsync() throws InterruptedException { | |||
Invocation invocation = DubboTestUtil.getDefaultMockInvocationOne(); | |||
Invoker invoker = DubboTestUtil.getDefaultMockInvoker(); | |||
when(invocation.getAttachment(ASYNC_KEY)).thenReturn(Boolean.TRUE.toString()); | |||
initDegradeRule(DubboUtils.getInterfaceName(invoker)); | |||
initDegradeRule(invoker.getUrl().getColonSeparatedKey()); | |||
Result result = requestGo(false, invocation); | |||
verifyInvocationStructureForAsyncCall(invoker, invocation); | |||
responseBack(result); | |||
Result result = invokeDubboRpc(false, invoker, invocation); | |||
verifyInvocationStructureForCallFinish(invoker, invocation); | |||
assertEquals("normal", result.getValue()); | |||
// inc the clusterNode's exception to trigger the fallback | |||
for (int i = 0; i < 5; i++) { | |||
responseBack(requestGo(true, invocation)); | |||
verifyInvocationStructureForCallFinish(); | |||
invokeDubboRpc(true, invoker, invocation); | |||
verifyInvocationStructureForCallFinish(invoker, invocation); | |||
} | |||
Result result2 = responseBack(requestGo(false, invocation)); | |||
Result result2 = invokeDubboRpc(false, invoker, invocation); | |||
assertEquals("fallback", result2.getValue()); | |||
// sleeping 1000 ms to reset exception | |||
Thread.sleep(1000); | |||
Result result3 = responseBack(requestGo(false, invocation)); | |||
Result result3 = invokeDubboRpc(false, invoker, invocation); | |||
assertEquals("normal", result3.getValue()); | |||
Context context = ContextUtil.getContext(); | |||
@@ -164,22 +138,26 @@ public class SentinelDubboConsumerFilterTest extends BaseTest { | |||
@Test | |||
public void testDegradeSync() throws InterruptedException { | |||
initDegradeRule(invoker.getUrl().getColonSeparatedKey()); | |||
Result result = requestGo(false, invocation); | |||
verifyInvocationStructure(invoker, invocation); | |||
responseBack(result); | |||
Invocation invocation = DubboTestUtil.getDefaultMockInvocationOne(); | |||
Invoker invoker = DubboTestUtil.getDefaultMockInvoker(); | |||
initDegradeRule(DubboUtils.getInterfaceName(invoker)); | |||
Result result = invokeDubboRpc(false, invoker, invocation); | |||
verifyInvocationStructureForCallFinish(invoker, invocation); | |||
assertEquals("normal", result.getValue()); | |||
// inc the clusterNode's exception to trigger the fallback | |||
for (int i = 0; i < 5; i++) { | |||
responseBack(requestGo(true, invocation)); | |||
verifyInvocationStructureForCallFinish(); | |||
invokeDubboRpc(true, invoker, invocation); | |||
verifyInvocationStructureForCallFinish(invoker, invocation); | |||
} | |||
Result result2 = responseBack(requestGo(false, invocation)); | |||
Result result2 = invokeDubboRpc(false, invoker, invocation); | |||
assertEquals("fallback", result2.getValue()); | |||
// sleeping 1000 ms to reset exception | |||
Thread.sleep(1000); | |||
Result result3 = responseBack(requestGo(false, invocation)); | |||
Result result3 = invokeDubboRpc(false, invoker, invocation); | |||
assertEquals("normal", result3.getValue()); | |||
Context context = ContextUtil.getContext(); | |||
@@ -189,62 +167,43 @@ public class SentinelDubboConsumerFilterTest extends BaseTest { | |||
@Test | |||
public void testMethodFlowControlAsync() { | |||
when(invocation.getAttachment(ASYNC_KEY)).thenReturn(Boolean.TRUE.toString()); | |||
initFlowRule(DubboUtils.getResourceName(invoker, invocation, DubboConfig.getDubboConsumerPrefix())); | |||
responseBack(requestGo(false, invocation)); | |||
responseBack(requestGo(false, invocation)); | |||
Invocation invocation = DubboTestUtil.getDefaultMockInvocationOne(); | |||
Invoker invoker = DubboTestUtil.getDefaultMockInvoker(); | |||
Invocation invocation2 = mock(Invocation.class); | |||
Method method = DemoService.class.getMethods()[1]; | |||
when(invocation2.getMethodName()).thenReturn(method.getName()); | |||
when(invocation2.getParameterTypes()).thenReturn(method.getParameterTypes()); | |||
Result result2 = responseBack(requestGo(false, invocation2)); | |||
verifyInvocationStructureForCallFinish(); | |||
when(invocation.getAttachment(ASYNC_KEY)).thenReturn(Boolean.TRUE.toString()); | |||
initFlowRule(consumerFilter.getMethodName(invoker, invocation)); | |||
invokeDubboRpc(false, invoker, invocation); | |||
invokeDubboRpc(false, invoker, invocation); | |||
Invocation invocation2 = DubboTestUtil.getDefaultMockInvocationTwo(); | |||
Result result2 = invokeDubboRpc(false, invoker, invocation2); | |||
verifyInvocationStructureForCallFinish(invoker, invocation2); | |||
assertEquals("normal", result2.getValue()); | |||
// the method of invocation should be blocked | |||
Result fallback = requestGo(false, invocation); | |||
assertNotNull(RpcContext.getContext().get(DubboUtils.DUBBO_INTERFACE_ENTRY_KEY)); | |||
assertNull(RpcContext.getContext().get(DubboUtils.DUBBO_METHOD_ENTRY_KEY)); | |||
responseBack(fallback); | |||
Result fallback = invokeDubboRpc(false, invoker, invocation); | |||
assertEquals("fallback", fallback.getValue()); | |||
verifyInvocationStructureForCallFinish(); | |||
verifyInvocationStructureForCallFinish(invoker, invocation); | |||
} | |||
public Result requestGo(boolean exception, Invocation currentInvocation) { | |||
AsyncRpcResult result = null; | |||
if (exception) { | |||
result = AsyncRpcResult.newDefaultAsyncResult(new Exception("error"), currentInvocation); | |||
} else { | |||
result = AsyncRpcResult.newDefaultAsyncResult("normal", currentInvocation); | |||
} | |||
when(invoker.invoke(currentInvocation)).thenReturn(result); | |||
return filter.invoke(invoker, currentInvocation); | |||
} | |||
public Result responseBack(Result result) { | |||
filter.listener().onMessage(result, invoker, invocation); | |||
return result; | |||
} | |||
@Test | |||
public void testInvokeAsync() throws InterruptedException { | |||
public void testInvokeAsync() { | |||
when(invocation.getAttachment(ASYNC_KEY)).thenReturn(Boolean.TRUE.toString()); | |||
Invocation invocation = DubboTestUtil.getDefaultMockInvocationOne(); | |||
Invoker invoker = DubboTestUtil.getDefaultMockInvoker(); | |||
when(invocation.getAttachment(ASYNC_KEY)).thenReturn(Boolean.TRUE.toString()); | |||
final Result result = mock(Result.class); | |||
when(result.hasException()).thenReturn(false); | |||
when(invoker.invoke(invocation)).thenAnswer(invocationOnMock -> { | |||
verifyInvocationStructureForAsyncCall(invoker, invocation); | |||
return result; | |||
return result; | |||
}); | |||
filter.invoke(invoker, invocation); | |||
consumerFilter.invoke(invoker, invocation); | |||
verify(invoker).invoke(invocation); | |||
Context context = ContextUtil.getContext(); | |||
@@ -254,6 +213,9 @@ public class SentinelDubboConsumerFilterTest extends BaseTest { | |||
@Test | |||
public void testInvokeSync() { | |||
Invocation invocation = DubboTestUtil.getDefaultMockInvocationOne(); | |||
Invoker invoker = DubboTestUtil.getDefaultMockInvoker(); | |||
final Result result = mock(Result.class); | |||
when(result.hasException()).thenReturn(false); | |||
when(result.getException()).thenReturn(new Exception()); | |||
@@ -262,14 +224,14 @@ public class SentinelDubboConsumerFilterTest extends BaseTest { | |||
return result; | |||
}); | |||
filter.invoke(invoker, invocation); | |||
consumerFilter.invoke(invoker, invocation); | |||
verify(invoker).invoke(invocation); | |||
filter.listener().onMessage(result, invoker, invocation); | |||
Context context = ContextUtil.getContext(); | |||
assertNull(context); | |||
} | |||
/** | |||
* Simply verify invocation structure in memory: | |||
* EntranceNode(defaultContextName) | |||
@@ -282,7 +244,7 @@ public class SentinelDubboConsumerFilterTest extends BaseTest { | |||
// 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, true); | |||
String resourceName = consumerFilter.getMethodName(invoker, invocation); | |||
assertEquals(com.alibaba.csp.sentinel.Constants.CONTEXT_DEFAULT_NAME, context.getName()); | |||
assertEquals("", context.getOrigin()); | |||
@@ -295,10 +257,10 @@ public class SentinelDubboConsumerFilterTest extends BaseTest { | |||
// As SphU.entry(interfaceName, EntryType.OUT); | |||
Set<Node> childList = entranceNode.getChildList(); | |||
assertEquals(1, childList.size()); | |||
DefaultNode interfaceNode = getNode(invoker.getUrl().getColonSeparatedKey(), entranceNode); | |||
DefaultNode interfaceNode = getNode(DubboUtils.getInterfaceName(invoker), entranceNode); | |||
ResourceWrapper interfaceResource = interfaceNode.getId(); | |||
assertEquals(invoker.getUrl().getColonSeparatedKey(), interfaceResource.getName()); | |||
assertEquals(DubboUtils.getInterfaceName(invoker), interfaceResource.getName()); | |||
assertSame(EntryType.OUT, interfaceResource.getEntryType()); | |||
// As SphU.entry(resourceName, EntryType.OUT); | |||
@@ -335,7 +297,7 @@ public class SentinelDubboConsumerFilterTest extends BaseTest { | |||
// 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, true); | |||
String resourceName = consumerFilter.getMethodName(invoker, invocation); | |||
assertEquals(com.alibaba.csp.sentinel.Constants.CONTEXT_DEFAULT_NAME, context.getName()); | |||
assertEquals("", context.getOrigin()); | |||
@@ -347,9 +309,9 @@ public class SentinelDubboConsumerFilterTest extends BaseTest { | |||
// As SphU.entry(interfaceName, EntryType.OUT); | |||
Set<Node> childList = entranceNode.getChildList(); | |||
assertEquals(2, childList.size()); | |||
DefaultNode interfaceNode = getNode(invoker.getUrl().getColonSeparatedKey(), entranceNode); | |||
DefaultNode interfaceNode = getNode(DubboUtils.getInterfaceName(invoker), entranceNode); | |||
ResourceWrapper interfaceResource = interfaceNode.getId(); | |||
assertEquals(invoker.getUrl().getColonSeparatedKey(), interfaceResource.getName()); | |||
assertEquals(DubboUtils.getInterfaceName(invoker), interfaceResource.getName()); | |||
assertSame(EntryType.OUT, interfaceResource.getEntryType()); | |||
// As SphU.entry(resourceName, EntryType.OUT); | |||
@@ -379,17 +341,16 @@ public class SentinelDubboConsumerFilterTest extends BaseTest { | |||
} | |||
private void verifyInvocationStructureForCallFinish() { | |||
private void verifyInvocationStructureForCallFinish(Invoker invoker, Invocation invocation) { | |||
Context context = ContextUtil.getContext(); | |||
assertNull(context); | |||
Entry interfaceEntry = (Entry) RpcContext.getContext().get(DubboUtils.DUBBO_INTERFACE_ENTRY_KEY); | |||
Entry methodEntry = (Entry) RpcContext.getContext().get(DubboUtils.DUBBO_METHOD_ENTRY_KEY); | |||
assertNull(interfaceEntry); | |||
assertNull(methodEntry); | |||
String methodResourceName = consumerFilter.getMethodName(invoker, invocation); | |||
Entry[] entries = (Entry[]) RpcContext.getContext().get(methodResourceName); | |||
assertNull(entries); | |||
} | |||
public DefaultNode getNode(String resourceName, DefaultNode root) { | |||
private DefaultNode getNode(String resourceName, DefaultNode root) { | |||
Queue<DefaultNode> queue = new LinkedList<>(); | |||
queue.offer(root); | |||
@@ -405,4 +366,52 @@ public class SentinelDubboConsumerFilterTest extends BaseTest { | |||
return null; | |||
} | |||
private void initFlowRule(String resource) { | |||
FlowRule flowRule = new FlowRule(resource); | |||
flowRule.setCount(1); | |||
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS); | |||
List<FlowRule> flowRules = new ArrayList<>(); | |||
flowRules.add(flowRule); | |||
FlowRuleManager.loadRules(flowRules); | |||
} | |||
private void initDegradeRule(String resource) { | |||
DegradeRule degradeRule = new DegradeRule(resource) | |||
.setCount(0.5) | |||
.setGrade(DEGRADE_GRADE_EXCEPTION_RATIO); | |||
List<DegradeRule> degradeRules = new ArrayList<>(); | |||
degradeRules.add(degradeRule); | |||
degradeRule.setTimeWindow(1); | |||
DegradeRuleManager.loadRules(degradeRules); | |||
} | |||
private void initFallback() { | |||
DubboFallbackRegistry.setConsumerFallback(new DubboFallback() { | |||
@Override | |||
public Result handle(Invoker<?> invoker, Invocation invocation, BlockException ex) { | |||
boolean async = RpcUtils.isAsync(invoker.getUrl(), invocation); | |||
Result fallbackResult = null; | |||
fallbackResult = AsyncRpcResult.newDefaultAsyncResult("fallback", invocation); | |||
return fallbackResult; | |||
} | |||
}); | |||
} | |||
private Result invokeDubboRpc(boolean exception, Invoker invoker, Invocation invocation) { | |||
Result result = null; | |||
InvokeMode invokeMode = RpcUtils.getInvokeMode(invoker.getUrl(), invocation); | |||
if (InvokeMode.SYNC == invokeMode) { | |||
result = exception ? new AppResponse(new Exception("error")) : new AppResponse("normal"); | |||
} else { | |||
result = exception ? AsyncRpcResult.newDefaultAsyncResult(new Exception("error"), invocation) : AsyncRpcResult.newDefaultAsyncResult("normal", invocation); | |||
} | |||
when(invoker.invoke(invocation)).thenReturn(result); | |||
return consumerFilter.invoke(invoker, invocation); | |||
} | |||
} |
@@ -16,6 +16,7 @@ | |||
package com.alibaba.csp.sentinel.adapter.dubbo; | |||
import com.alibaba.csp.sentinel.BaseTest; | |||
import com.alibaba.csp.sentinel.DubboTestUtil; | |||
import com.alibaba.csp.sentinel.Entry; | |||
import com.alibaba.csp.sentinel.EntryType; | |||
import com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService; | |||
@@ -35,52 +36,49 @@ import org.junit.After; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import java.lang.reflect.Method; | |||
import java.util.Map; | |||
import java.util.Set; | |||
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; | |||
import static org.junit.Assert.*; | |||
import static org.mockito.Mockito.*; | |||
/** | |||
* @author cdfive | |||
* @author lianglin | |||
*/ | |||
public class SentinelDubboProviderFilterTest extends BaseTest { | |||
private SentinelDubboProviderFilter filter = new SentinelDubboProviderFilter(); | |||
@Before | |||
public void setUp() { | |||
constructInvokerAndInvocation(); | |||
cleanUpAll(); | |||
} | |||
@After | |||
public void cleanUp() { | |||
public void destroy() { | |||
cleanUpAll(); | |||
} | |||
@Test | |||
public void testInvoke() { | |||
final String originApplication = "consumerA"; | |||
URL url = invoker.getUrl() | |||
.addParameter(CommonConstants.SIDE_KEY, CommonConstants.PROVIDER_SIDE); | |||
when(invoker.getUrl()).thenReturn(url); | |||
URL url = DubboTestUtil.getDefaultTestURL(); | |||
url = url.addParameter(CommonConstants.SIDE_KEY, CommonConstants.PROVIDER_SIDE); | |||
Invoker invoker = DubboTestUtil.getMockInvoker(url, DemoService.class); | |||
Invocation invocation = DubboTestUtil.getMockInvocation(DemoService.class.getMethods()[0]); | |||
when(invocation.getAttachment(DubboUtils.SENTINEL_DUBBO_APPLICATION_KEY, "")) | |||
.thenReturn(originApplication); | |||
final Result result = mock(Result.class); | |||
when(result.hasException()).thenReturn(false); | |||
when(result.getException()).thenReturn(new Exception()); | |||
when(invoker.invoke(invocation)).thenAnswer(invocationOnMock -> { | |||
verifyInvocationStructure(originApplication, invoker, invocation); | |||
return result; | |||
@@ -89,29 +87,28 @@ public class SentinelDubboProviderFilterTest extends BaseTest { | |||
filter.invoke(invoker, invocation); | |||
verify(invoker).invoke(invocation); | |||
filter.listener().onMessage(result, invoker, invocation); | |||
Context context = ContextUtil.getContext(); | |||
assertNull(context); | |||
} | |||
/** | |||
* Simply verify invocation structure in memory: | |||
* EntranceNode(resourceName) | |||
* EntranceNode(methodResourceName) | |||
* --InterfaceNode(interfaceName) | |||
* ----MethodNode(resourceName) | |||
* ----MethodNode(methodResourceName) | |||
*/ | |||
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, true); | |||
assertEquals(resourceName, context.getName()); | |||
String methodResourceName = filter.getMethodName(invoker, invocation); | |||
assertEquals(methodResourceName, context.getName()); | |||
assertEquals(originApplication, context.getOrigin()); | |||
DefaultNode entranceNode = context.getEntranceNode(); | |||
ResourceWrapper entranceResource = entranceNode.getId(); | |||
assertEquals(resourceName, entranceResource.getName()); | |||
assertEquals(methodResourceName, entranceResource.getName()); | |||
assertSame(EntryType.IN, entranceResource.getEntryType()); | |||
// As SphU.entry(interfaceName, EntryType.IN); | |||
@@ -120,7 +117,7 @@ public class SentinelDubboProviderFilterTest extends BaseTest { | |||
DefaultNode interfaceNode = (DefaultNode) childList.iterator().next(); | |||
ResourceWrapper interfaceResource = interfaceNode.getId(); | |||
assertEquals(invoker.getUrl().getColonSeparatedKey(), interfaceResource.getName()); | |||
assertEquals(filter.getInterfaceName(invoker), interfaceResource.getName()); | |||
assertSame(EntryType.IN, interfaceResource.getEntryType()); | |||
// As SphU.entry(resourceName, EntryType.IN, 1, invocation.getArguments()); | |||
@@ -128,7 +125,7 @@ public class SentinelDubboProviderFilterTest extends BaseTest { | |||
assertEquals(1, childList.size()); | |||
DefaultNode methodNode = (DefaultNode) childList.iterator().next(); | |||
ResourceWrapper methodResource = methodNode.getId(); | |||
assertEquals(resourceName, methodResource.getName()); | |||
assertEquals(methodResourceName, methodResource.getName()); | |||
assertSame(EntryType.IN, methodResource.getEntryType()); | |||
// Verify curEntry | |||
@@ -151,4 +148,6 @@ public class SentinelDubboProviderFilterTest extends BaseTest { | |||
assertEquals(1, interfaceOriginCountMap.size()); | |||
assertTrue(interfaceOriginCountMap.containsKey(originApplication)); | |||
} | |||
} |