package io.craft.atom.rpc;
import io.craft.atom.io.AbstractIoHandler;
import io.craft.atom.io.Channel;
import io.craft.atom.io.IoConnector;
import io.craft.atom.nio.api.NioFactory;
import io.craft.atom.rpc.DefaultRpcClient;
import io.craft.atom.rpc.DefaultRpcConnector;
import io.craft.atom.rpc.RpcException;
import io.craft.atom.rpc.api.RpcClient;
import io.craft.atom.rpc.api.RpcClientX;
import io.craft.atom.rpc.api.RpcContext;
import io.craft.atom.rpc.api.RpcFactory;
import io.craft.atom.rpc.api.RpcParameter;
import io.craft.atom.rpc.api.RpcServer;
import io.craft.atom.rpc.api.RpcServerX;
import io.craft.atom.rpc.spi.RpcApi;
import io.craft.atom.test.AvailablePortFinder;
import io.craft.atom.test.CaseCounter;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
/**
* Test for RPC
*
* @author mindwind
* @version 1.0, Sep 5, 2014
*/
public class TestRpc {
private DemoService ds ;
private RpcServer server;
private RpcClient client;
private String host ;
private int port ;
@Before
public void before() {
host = "localhost";
port = AvailablePortFinder.getNextAvailable();
server = RpcFactory.newRpcServer(port);
server.export(DemoService.class, new DemoServiceImpl1(), new RpcParameter(10, 100));
server.open();
client = RpcFactory.newRpcClient(host, port);
client.open();
ds = client.refer(DemoService.class);
}
@Test
public void testBasic() {
String hi = ds.echo("hi");
Assert.assertEquals("hi", hi);
System.out.println(String.format("[CRAFT-ATOM-NIO] (^_^) <%s> Case -> test basic. ", CaseCounter.incr(1)));
}
@Test
public void testInMultiThreads() throws InterruptedException {
int count = 20;
final CountDownLatch latch = new CountDownLatch(count);
final AtomicBoolean flag = new AtomicBoolean(true);
Executor executor = Executors.newFixedThreadPool(100);
for (int i = 0; i < count; i++) {
executor.execute(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
String hi = Thread.currentThread().getId() + "-hi-" + i;
String ret = ds.echo(hi);
if (!hi.equals(ret)) {
flag.set(false);
}
}
latch.countDown();
}
});
}
latch.await();
Assert.assertTrue(flag.get());
System.out.println(String.format("[CRAFT-ATOM-NIO] (^_^) <%s> Case -> test in multi threads. ", CaseCounter.incr(1)));
}
@Test
public void testTimeout() throws InterruptedException {
RpcContext.getContext().setRpcTimeoutInMillis(100);
try {
ds.timeout("hi");
Assert.fail();
} catch (RpcException e) {
Assert.assertTrue(RpcException.CLIENT_TIMEOUT == e.getCode() || RpcException.SERVER_TIMEOUT == e.getCode());
}
System.out.println(String.format("[CRAFT-ATOM-NIO] (^_^) <%s> Case -> test timeout. ", CaseCounter.incr(1)));
}
@Test
public void testVoid() {
ds.noreturn("hi");
Assert.assertTrue(true);
System.out.println(String.format("[CRAFT-ATOM-NIO] (^_^) <%s> Case -> test void. ", CaseCounter.incr(1)));
}
@Test
public void testAttachment() {
RpcContext.getContext().setAttachment("demo", "demo");
String atta = ds.attachment();
Assert.assertEquals("demo", atta);
System.out.println(String.format("[CRAFT-ATOM-NIO] (^_^) <%s> Case -> test attachment. ", CaseCounter.incr(1)));
}
@Test
public void testOneway() throws InterruptedException {
RpcContext.getContext().setOneway(true);
String r = ds.oneway();
Assert.assertNull(r);
Thread.sleep(100);
System.out.println(String.format("[CRAFT-ATOM-NIO] (^_^) <%s> Case -> test oneway. ", CaseCounter.incr(1)));
}
@Test
public void testMultiConnections() {
client = RpcFactory.newRpcClientBuilder(host, port).connections(10).build();
client.open();
ds = client.refer(DemoService.class);
for (int i = 0; i < 20; i++) {
String hi = ds.echo("hi-" + i);
Assert.assertEquals("hi-" + i, hi);
}
System.out.println(String.format("[CRAFT-ATOM-NIO] (^_^) <%s> Case -> test multi connections. ", CaseCounter.incr(1)));
}
@Test
public void testMaxAcceptConnections() throws Exception {
int connections = 100;
port = AvailablePortFinder.getNextAvailable(33333);
server = RpcFactory.newRpcServerBuilder(port).connections(connections).build();
server.open();
for (int i = 0; i < connections; i++) { new Socket("127.0.0.1", port); }
Thread.sleep(50);
IoConnector connector = NioFactory.newTcpConnector(new AbstractIoHandler() {});
Future<Channel<byte[]>> future = connector.connect("127.0.0.1", port);
Channel<byte[]> channel = future.get(200, TimeUnit.MILLISECONDS);
Thread.sleep(50);
Assert.assertFalse(channel.isOpen());
System.out.println(String.format("[CRAFT-ATOM-NIO] (^_^) <%s> Case -> test max accept connections. ", CaseCounter.incr(1)));
}
@Test
public void testBrokenConnectionAndReconnect() throws InterruptedException {
int conns = 10;
client = RpcFactory.newRpcClientBuilder(host, port).connections(conns).build();
client.open();
ds = client.refer(DemoService.class);
DefaultRpcConnector connector = (DefaultRpcConnector) ((DefaultRpcClient) client).getConnector();
connector.setAllowReconnect(false);
connector.setReconnectDelay(10);
connector.brokeAll();
try {
ds.echo("hi");
} catch (RpcException e) {
Assert.assertEquals(RpcException.NETWORK, e.getCode());
}
connector.setAllowReconnect(true);
Thread.sleep(100);
int ac = connector.aliveConnectionNum();
Assert.assertEquals(conns, ac);
String hello = ds.echo("hello");
Assert.assertEquals("hello", hello);
System.out.println(String.format("[CRAFT-ATOM-NIO] (^_^) <%s> Case -> test broken connection and reconnect. ", CaseCounter.incr(3)));
}
@Test
public void testHeartbeat() throws InterruptedException {
port = AvailablePortFinder.getNextAvailable();
server = RpcFactory.newRpcServerBuilder(port).ioTimeoutInMillis(100).build();
server.export(DemoService.class, new DemoServiceImpl1(), new RpcParameter());
server.open();
client = RpcFactory.newRpcClient(host, port);
client.open();
ds = client.refer(DemoService.class);
DefaultRpcConnector connector = (DefaultRpcConnector) ((DefaultRpcClient) client).getConnector();
connector.setAllowReconnect(false);
Thread.sleep(220);
// no heartbeat
try {
ds.echo("hi");
Assert.fail();
} catch (RpcException e) {
Assert.assertEquals(RpcException.NETWORK, e.getCode());
}
// heartbeat
client = RpcFactory.newRpcClientBuilder(host, port).heartbeatInMillis(50).build();
client.open();
ds = client.refer(DemoService.class);
Thread.sleep(210);
String hi = ds.echo("hi");
Assert.assertEquals("hi", hi);
System.out.println(String.format("[CRAFT-ATOM-NIO] (^_^) <%s> Case -> test heartbeat. ", CaseCounter.incr(2)));
}
@Test
public void testOverload() throws InterruptedException {
Executor executor = Executors.newCachedThreadPool();
for (int i = 0; i < 11; i++) {
executor.execute(new Runnable() {
@Override
public void run() {
try { ds.overload(); } catch (InterruptedException e) {}
}
});
}
Thread.sleep(100);
try {
ds.overload();
} catch (RpcException e) {
Assert.assertEquals(RpcException.SERVER_OVERLOAD, e.getCode());
}
}
@Test
public void testBizException() {
try {
ds.bizException();
Assert.fail();
} catch (IllegalAccessException e) {
Assert.assertTrue(true);
}
System.out.println(String.format("[CRAFT-ATOM-NIO] (^_^) <%s> Case -> test biz exception. ", CaseCounter.incr(1)));
}
@Test
public void testError() {
try {
ds.error();
Assert.fail();
} catch (RpcException e) {
Assert.assertEquals(RpcException.SERVER_ERROR, e.getCode());
}
System.out.println(String.format("[CRAFT-ATOM-NIO] (^_^) <%s> Case -> test error. ", CaseCounter.incr(1)));
}
@Test
public void testUndeclaredException() {
try {
ds.undeclaredException();
Assert.fail();
} catch (RpcException e) {
Assert.assertEquals(RpcException.SERVER_ERROR, e.getCode());
}
System.out.println(String.format("[CRAFT-ATOM-NIO] (^_^) <%s> Case -> test undeclared exception. ", CaseCounter.incr(1)));
}
@Test
public void testRt() {
// remote
RpcContext.getContext().setRpcTimeoutInMillis(5000);
ds.echo("hi");
long s = System.nanoTime();
for (int i = 0; i < 100; i++) {
ds.echo("hi");
}
long e = System.nanoTime();
long rrt = e - s;
// local
ds = new DemoServiceImpl1();
s = System.nanoTime();
for (int i = 0; i < 100; i++) {
ds.echo("hi");
}
e = System.nanoTime();
long lrt = e - s;
Assert.assertTrue(rrt > lrt);
System.out.println(String.format("[CRAFT-ATOM-NIO] (^_^) <%s> Case -> test rt |local=%s, remote=%s| ns. ", CaseCounter.incr(1), lrt, rrt));
}
@Test
public void testMultipleImplementor() {
server.export("ds2", DemoService.class, new DemoServiceImpl2(), new RpcParameter());
String hi = ds.echo("hi");
Assert.assertEquals("hi", hi);
RpcContext.getContext().setRpcId("ds2");
String hihi = ds.echo("hi");
Assert.assertEquals("hihi", hihi);
System.out.println(String.format("[CRAFT-ATOM-NIO] (^_^) <%s> Case -> test multiple implementor. ", CaseCounter.incr(2)));
}
@Test
public void testAsync() throws Exception {
// Async two-way
RpcContext ctx = RpcContext.getContext();
ctx.setAsync(true);
String r = ds.echo("hi");
Assert.assertNull(r);
Future<String> future = ctx.getFuture();
r = future.get(2, TimeUnit.SECONDS);
Assert.assertEquals("hi", r);
// Async one-way
ctx = RpcContext.getContext();
ctx.setAsync(true);
ctx.setOneway(true);
r = ds.echo("hi");
Assert.assertNull(r);
future = ctx.getFuture();
Assert.assertNull(future);
System.out.println(String.format("[CRAFT-ATOM-NIO] (^_^) <%s> Case -> test async. ", CaseCounter.incr(4)));
}
@Test
public void testPartialExported() {
port = AvailablePortFinder.getNextAvailable(33333);
server = RpcFactory.newRpcServerBuilder(port).build();
server.open();
server.export(DemoService.class, "echo", new Class<?>[] { String.class }, new DemoServiceImpl1(), new RpcParameter(10, 100));
client = RpcFactory.newRpcClient(host, port);
client.open();
ds = client.refer(DemoService.class);
String hi = ds.echo("hi");
Assert.assertEquals("hi", hi);
try {
ds.noreturn("hello");
Assert.fail();
} catch (RpcException e) {
Assert.assertEquals(RpcException.SERVER_ERROR, e.getCode());
}
System.out.println(String.format("[CRAFT-ATOM-NIO] (^_^) <%s> Case -> test partial exported. ", CaseCounter.incr(2)));
}
@Test
public void testServerX() {
ds.echo("hi");
RpcServerX x = server.x();
Set<RpcApi> apis = x.apis();
Assert.assertEquals(1, x.connectionCount());
for (RpcApi api : apis) {
if (api.getMethodName().equals("echo")) {
Assert.assertEquals(0, x.waitCount(api));
Assert.assertEquals(0, x.processingCount(api));
Assert.assertEquals(1, x.completeCount(api));
}
}
System.out.println(String.format("[CRAFT-ATOM-NIO] (^_^) <%s> Case -> test server x. ", CaseCounter.incr(4)));
}
@Test
public void testClientX() {
ds.echo("hi");
RpcClientX x = client.x();
int wc = x.waitCount();
Assert.assertEquals(0, wc);
System.out.println(String.format("[CRAFT-ATOM-NIO] (^_^) <%s> Case -> test client x. ", CaseCounter.incr(1)));
}
@Test
public void testClose() throws UnknownHostException, IOException {
client.close();
server.close();
try {
new Socket(host, port);
} catch (IOException e) {
Assert.assertTrue(true);
}
System.out.println(String.format("[CRAFT-ATOM-NIO] (^_^) <%s> Case -> test close. ", CaseCounter.incr(1)));
}
@Test
public void testUnexport() {
server.unexport(DemoService.class, "echo", new Class<?>[] { String.class });
try {
ds.echo("hi");
} catch (RpcException e) {
Assert.assertEquals(RpcException.SERVER_ERROR, e.getCode());
}
ds.noreturn("hello");
Assert.assertTrue(true);
System.out.println(String.format("[CRAFT-ATOM-NIO] (^_^) <%s> Case -> test unexport. ", CaseCounter.incr(2)));
}
}