/* | |
* Copyright 1999-2011 Alibaba Group. | |
* | |
* 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.dubbo.rpc.cluster.support; | |
import static org.junit.Assert.assertEquals; | |
import static org.junit.Assert.assertFalse; | |
import static org.junit.Assert.assertSame; | |
import static org.junit.Assert.assertTrue; | |
import static org.junit.Assert.fail; | |
import java.util.ArrayList; | |
import java.util.List; | |
import java.util.concurrent.Callable; | |
import org.easymock.EasyMock; | |
import org.junit.Before; | |
import org.junit.Test; | |
import com.alibaba.dubbo.common.URL; | |
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 com.alibaba.dubbo.rpc.RpcInvocation; | |
import com.alibaba.dubbo.rpc.RpcResult; | |
import com.alibaba.dubbo.rpc.cluster.Directory; | |
import com.alibaba.dubbo.rpc.cluster.directory.StaticDirectory; | |
import com.alibaba.dubbo.rpc.protocol.AbstractInvoker; | |
/** | |
* FailoverClusterInvokerTest | |
* @author liuchao | |
* | |
*/ | |
@SuppressWarnings("unchecked") | |
public class FailoverClusterInvokerTest { | |
List<Invoker<FailoverClusterInvokerTest>> invokers = new ArrayList<Invoker<FailoverClusterInvokerTest>>(); | |
int retries = 5; | |
URL url = URL.valueOf("test://test:11/test?retries="+retries); | |
Invoker<FailoverClusterInvokerTest> invoker1 = EasyMock.createMock(Invoker.class); | |
Invoker<FailoverClusterInvokerTest> invoker2 = EasyMock.createMock(Invoker.class); | |
RpcInvocation invocation = new RpcInvocation(); | |
Directory<FailoverClusterInvokerTest> dic ; | |
Result result = new RpcResult(); | |
/** | |
* @throws java.lang.Exception | |
*/ | |
@Before | |
public void setUp() throws Exception { | |
dic = EasyMock.createMock(Directory.class); | |
EasyMock.expect(dic.getUrl()).andReturn(url).anyTimes(); | |
EasyMock.expect(dic.list(invocation)).andReturn(invokers).anyTimes(); | |
EasyMock.expect(dic.getInterface()).andReturn(FailoverClusterInvokerTest.class).anyTimes(); | |
invocation.setMethodName("method1"); | |
EasyMock.replay(dic); | |
invokers.add(invoker1); | |
invokers.add(invoker2); | |
} | |
@Test | |
public void testInvokeWithRuntimeException() { | |
EasyMock.reset(invoker1); | |
EasyMock.expect(invoker1.invoke(invocation)).andThrow(new RuntimeException()).anyTimes(); | |
EasyMock.expect(invoker1.isAvailable()).andReturn(true).anyTimes(); | |
EasyMock.expect(invoker1.getUrl()).andReturn(url).anyTimes(); | |
EasyMock.expect(invoker1.getInterface()).andReturn(FailoverClusterInvokerTest.class).anyTimes(); | |
EasyMock.replay(invoker1); | |
EasyMock.reset(invoker2); | |
EasyMock.expect(invoker2.invoke(invocation)).andThrow(new RuntimeException()).anyTimes(); | |
EasyMock.expect(invoker2.isAvailable()).andReturn(true).anyTimes(); | |
EasyMock.expect(invoker2.getUrl()).andReturn(url).anyTimes(); | |
EasyMock.expect(invoker2.getInterface()).andReturn(FailoverClusterInvokerTest.class).anyTimes(); | |
EasyMock.replay(invoker2); | |
FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<FailoverClusterInvokerTest>(dic); | |
try { | |
invoker.invoke(invocation); | |
fail(); | |
} catch (RpcException expected) { | |
assertEquals(0,expected.getCode()); | |
assertFalse(expected.getCause() instanceof RpcException); | |
} | |
} | |
@Test() | |
public void testInvokeWithRPCException() { | |
EasyMock.reset(invoker1); | |
EasyMock.expect(invoker1.invoke(invocation)).andThrow(new RpcException()).anyTimes(); | |
EasyMock.expect(invoker1.isAvailable()).andReturn(true).anyTimes(); | |
EasyMock.expect(invoker1.getUrl()).andReturn(url).anyTimes(); | |
EasyMock.expect(invoker1.getInterface()).andReturn(FailoverClusterInvokerTest.class).anyTimes(); | |
EasyMock.replay(invoker1); | |
EasyMock.reset(invoker2); | |
EasyMock.expect(invoker2.invoke(invocation)).andReturn(result).anyTimes(); | |
EasyMock.expect(invoker2.isAvailable()).andReturn(true).anyTimes(); | |
EasyMock.expect(invoker2.getUrl()).andReturn(url).anyTimes(); | |
EasyMock.expect(invoker2.getInterface()).andReturn(FailoverClusterInvokerTest.class).anyTimes(); | |
EasyMock.replay(invoker2); | |
FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<FailoverClusterInvokerTest>(dic); | |
for(int i=0;i<100;i++){ | |
Result ret = invoker.invoke(invocation); | |
assertSame(result, ret); | |
} | |
} | |
@Test() | |
public void testInvoke_retryTimes() { | |
EasyMock.reset(invoker1); | |
EasyMock.expect(invoker1.invoke(invocation)).andThrow(new RpcException(RpcException.TIMEOUT_EXCEPTION)).anyTimes(); | |
EasyMock.expect(invoker1.isAvailable()).andReturn(false).anyTimes(); | |
EasyMock.expect(invoker1.getUrl()).andReturn(url).anyTimes(); | |
EasyMock.expect(invoker1.getInterface()).andReturn(FailoverClusterInvokerTest.class).anyTimes(); | |
EasyMock.replay(invoker1); | |
EasyMock.reset(invoker2); | |
EasyMock.expect(invoker2.invoke(invocation)).andThrow(new RpcException()).anyTimes(); | |
EasyMock.expect(invoker2.isAvailable()).andReturn(false).anyTimes(); | |
EasyMock.expect(invoker2.getUrl()).andReturn(url).anyTimes(); | |
EasyMock.expect(invoker2.getInterface()).andReturn(FailoverClusterInvokerTest.class).anyTimes(); | |
EasyMock.replay(invoker2); | |
FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<FailoverClusterInvokerTest>(dic); | |
try{ | |
Result ret = invoker.invoke(invocation); | |
assertSame(result, ret); | |
fail(); | |
}catch (RpcException expected) { | |
assertTrue(expected.isTimeout()); | |
assertTrue(expected.getMessage().indexOf((retries+1)+" times")>0); | |
} | |
} | |
@Test() | |
public void testNoInvoke() { | |
dic = EasyMock.createMock(Directory.class); | |
EasyMock.expect(dic.getUrl()).andReturn(url).anyTimes(); | |
EasyMock.expect(dic.list(invocation)).andReturn(null).anyTimes(); | |
EasyMock.expect(dic.getInterface()).andReturn(FailoverClusterInvokerTest.class).anyTimes(); | |
invocation.setMethodName("method1"); | |
EasyMock.replay(dic); | |
invokers.add(invoker1); | |
FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<FailoverClusterInvokerTest>(dic); | |
try { | |
invoker.invoke(invocation); | |
fail(); | |
} catch (RpcException expected) { | |
assertFalse(expected.getCause() instanceof RpcException); | |
} | |
} | |
/** | |
* 测试在调用重试过程中,directory列表变更,invoke重试时重新进行list选择 | |
*/ | |
@Test | |
public void testInvokerDestoryAndReList(){ | |
final URL url = URL.valueOf("test://localhost/"+ Demo.class.getName() + "?loadbalance=roundrobin&retries="+retries); | |
RpcException exception = new RpcException(RpcException.TIMEOUT_EXCEPTION); | |
MockInvoker<Demo> invoker1 = new MockInvoker<Demo>(Demo.class, url); | |
invoker1.setException(exception); | |
MockInvoker<Demo> invoker2 = new MockInvoker<Demo>(Demo.class, url); | |
invoker2.setException(exception); | |
final List<Invoker<Demo>> invokers = new ArrayList<Invoker<Demo>>(); | |
invokers.add(invoker1); | |
invokers.add(invoker2); | |
Callable<Object> callable = new Callable<Object>() { | |
public Object call() throws Exception { | |
//模拟invoker全部被destroy掉 | |
for (Invoker<Demo> invoker:invokers){ | |
invoker.destroy(); | |
} | |
invokers.clear(); | |
MockInvoker<Demo> invoker3 = new MockInvoker<Demo>(Demo.class, url); | |
invokers.add(invoker3); | |
return null; | |
} | |
}; | |
invoker1.setCallable(callable); | |
invoker2.setCallable(callable); | |
RpcInvocation inv = new RpcInvocation(); | |
inv.setMethodName("test"); | |
Directory<Demo> dic = new MockDirectory<Demo>(url, invokers); | |
FailoverClusterInvoker<Demo> clusterinvoker = new FailoverClusterInvoker<Demo>(dic); | |
clusterinvoker.invoke(inv); | |
} | |
public static interface Demo{} | |
public static class MockInvoker<T> extends AbstractInvoker<T> { | |
URL url; | |
boolean available = true; | |
boolean destoryed = false; | |
Result result ; | |
RpcException exception; | |
Callable<?> callable; | |
public MockInvoker(Class<T> type, URL url) { | |
super(type, url); | |
} | |
public void setResult(Result result) { | |
this.result = result; | |
} | |
public void setException(RpcException exception) { | |
this.exception = exception; | |
} | |
public void setCallable(Callable<?> callable) { | |
this.callable = callable; | |
} | |
@Override | |
protected Result doInvoke(Invocation invocation) throws Throwable { | |
if (callable != null) { | |
try { | |
callable.call(); | |
} catch (Exception e) { | |
throw new RpcException(e); | |
} | |
} | |
if (exception != null) { | |
throw exception; | |
} else { | |
return result; | |
} | |
} | |
} | |
public class MockDirectory<T> extends StaticDirectory<T> { | |
public MockDirectory(URL url , List<Invoker<T>> invokers) { | |
super(url, invokers); | |
} | |
@Override | |
protected List<Invoker<T>> doList(Invocation invocation) throws RpcException { | |
return new ArrayList<Invoker<T>>(super.doList(invocation)); | |
} | |
} | |
} |