package org.jgroups.tests;
import org.jgroups.*;
import org.jgroups.blocks.MethodCall;
import org.jgroups.blocks.RequestOptions;
import org.jgroups.blocks.ResponseMode;
import org.jgroups.blocks.RpcDispatcher;
import org.jgroups.protocols.*;
import org.jgroups.protocols.pbcast.GMS;
import org.jgroups.protocols.pbcast.NAKACK2;
import org.jgroups.protocols.relay.RELAY2;
import org.jgroups.protocols.relay.Route;
import org.jgroups.protocols.relay.SiteMaster;
import org.jgroups.protocols.relay.config.RelayConfig;
import org.jgroups.stack.Protocol;
import org.jgroups.util.RspList;
import org.jgroups.util.Util;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import java.util.ArrayList;
import java.util.List;
/**
* Various RELAY2-related tests
* @author Bela Ban
* @since 3.2
*/
@Test(groups=Global.FUNCTIONAL,singleThreaded=true)
public class Relay2RpcDispatcherTest {
protected JChannel a, b; // members in site "lon"
protected JChannel x, y; // members in site "sfo
protected RpcDispatcher rpca, rpcb; // rpc in site "lon"
protected RpcDispatcher rpcx, rpcy; // rpc in site "sfo"
protected MyReceiver al, bl; // receiver in site "lon"
protected MyReceiver xl, yl; // receiver in site "sfo"
protected static final String BRIDGE_CLUSTER = "global";
protected static final String LON_CLUSTER = "lon-cluster";
protected static final String SFO_CLUSTER = "sfo-cluster";
protected static final String SFO = "sfo", LON="lon";
@BeforeMethod
protected void setUp() throws Exception {
a = createNode(LON, "A");
b = createNode(LON, "B");
al=new MyReceiver("A");
bl=new MyReceiver("B");
rpca = new RpcDispatcher(a, new ServerObject(1)).setMembershipListener(al);
rpcb = new RpcDispatcher(b, new ServerObject(1)).setMembershipListener(bl);
x = createNode(SFO, "X");
y = createNode(SFO, "Y");
xl=new MyReceiver("X");
yl=new MyReceiver("Y");
rpcx = new RpcDispatcher(x, new ServerObject(1)).setMembershipListener(xl);
rpcy = new RpcDispatcher(y, new ServerObject(1)).setMembershipListener(yl);
}
@AfterMethod protected void destroy() {Util.close(y,x,b,a);}
public void testRpcToUnknownSite() throws Exception {
a.connect(LON_CLUSTER);
try {
rpca.callRemoteMethod(new SiteMaster("nyc"),"foo",null,null,RequestOptions.SYNC());
assert false : "The RPC should have thrown an UnreachableException";
}
catch(UnreachableException unreachable) {
System.out.println("caught " + unreachable.getClass().getSimpleName() + " - as expected");
}
}
/**
* Tests that notifications are routed to all sites.
*/
public void testNotificationAndRpcRelay2Transit() throws Exception {
a.connect(LON_CLUSTER);
b.connect(LON_CLUSTER);
rpca.start();
rpcb.start();
Util.waitUntilAllChannelsHaveSameView(30000, 1000, a, b);
x.connect(SFO_CLUSTER);
y.connect(SFO_CLUSTER);
rpcx.start();
rpcy.start();
Util.waitUntilAllChannelsHaveSameView(30000, 1000, x, y);
assert a.getView().size() == 2;
assert x.getView().size() == 2;
RELAY2 ar=a.getProtocolStack().findProtocol(RELAY2.class);
RELAY2 xr=x.getProtocolStack().findProtocol(RELAY2.class);
assert ar != null && xr != null;
JChannel a_bridge=null, x_bridge=null;
for(int i=0; i < 20; i++) {
a_bridge=ar.getBridge(SFO);
x_bridge=xr.getBridge(LON);
if(a_bridge != null && x_bridge != null && a_bridge.getView().size() == 2 && x_bridge.getView().size() == 2)
break;
Util.sleep(500);
}
assert a_bridge != null && x_bridge != null;
System.out.println("A's bridge channel: " + a_bridge.getView());
System.out.println("X's bridge channel: " + x_bridge.getView());
assert a_bridge.getView().size() == 2 : "bridge view is " + a_bridge.getView();
assert x_bridge.getView().size() == 2 : "bridge view is " + x_bridge.getView();
Route route=getRoute(x, LON);
System.out.println("Route at sfo to lon: " + route);
assert route != null;
System.out.println("B: sending message 0 to the site master of SFO");
Address sm_sfo=new SiteMaster(SFO);
MethodCall call=new MethodCall(ServerObject.class.getMethod("foo"));
System.out.println("B: call foo method on A");
Object rsp = rpcb.callRemoteMethod(a.getAddress(), call, new RequestOptions(ResponseMode.GET_ALL,5000));
System.out.println("RSP is: " + rsp );
System.out.println("B: call foo method on SFO master site");
rsp = rpcb.callRemoteMethod(sm_sfo, call, new RequestOptions(ResponseMode.GET_ALL,15000));
System.out.println("RSP is: " + rsp );
System.out.println("B: call foo method on all members in site LON");
RspList<Integer> rsps = rpcb.callRemoteMethods(null, call, new RequestOptions(ResponseMode.GET_ALL,5000));
System.out.println("RSPs are: \n" + rsps);
assert rsps.size() == 2;
assert rsps.containsKey(a.getAddress()) && rsps.containsKey(b.getAddress());
View bridge_view=xr.getBridgeView(BRIDGE_CLUSTER);
System.out.println("bridge_view = " + bridge_view);
route=getRoute(x, LON);
System.out.println("Route at sfo to lon: " + route);
assert route != null;
}
private static void checkMsgDelivery(MyReceiver... rl) {
for(MyReceiver r : rl) {
List<Integer> list=r.getList();
for(int i=0; i < 20; i++) {
if(!list.isEmpty())
break;
Util.sleep(500);
}
System.out.println("list = " + list);
assert list.size() == 1 && list.get(0) == 0;
r.clear();
}
}
protected JChannel createNode(String site_name, String node_name) throws Exception {
JChannel ch=new JChannel(new SHARED_LOOPBACK(),
new SHARED_LOOPBACK_PING(),
new MERGE3().setValue("max_interval", 3000).setValue("min_interval", 1000),
new NAKACK2(),
new UNICAST3(),
new GMS().setValue("print_local_addr", false),
new FORWARD_TO_COORD(),
createRELAY2(site_name));
ch.setName(node_name);
return ch;
}
protected static class ServerObject {
protected int i;
public ServerObject(int i) {
this.i=i;
}
public int foo() {
System.out.println("foo()");
return i;
}
public static long sleep(long timeout) {
long start=System.currentTimeMillis();
Util.sleep(timeout);
return System.currentTimeMillis() - start;
}
}
protected RELAY2 createRELAY2(String site_name) {
RELAY2 relay=new RELAY2().site(site_name).enableAddressTagging(false).asyncRelayCreation(true).relayMulticasts(true);
RelayConfig.SiteConfig lon_cfg=new RelayConfig.SiteConfig(LON),
sfo_cfg=new RelayConfig.SiteConfig(SFO);
lon_cfg.addBridge(new RelayConfig.ProgrammaticBridgeConfig(BRIDGE_CLUSTER, createBridgeStack()));
sfo_cfg.addBridge(new RelayConfig.ProgrammaticBridgeConfig(BRIDGE_CLUSTER, createBridgeStack()));
relay.addSite(LON, lon_cfg).addSite(SFO, sfo_cfg);
return relay;
}
protected static Protocol[] createBridgeStack() {
return new Protocol[]{
new SHARED_LOOPBACK(),
new SHARED_LOOPBACK_PING(),
new NAKACK2(),
new UNICAST3(),
new GMS().setValue("print_local_addr", false)
};
}
/** Creates a singleton view for each channel listed and injects it */
protected static void createPartition(JChannel ... channels) {
for(JChannel ch: channels) {
View view=View.create(ch.getAddress(), 5, ch.getAddress());
GMS gms=ch.getProtocolStack().findProtocol(GMS.class);
gms.installView(view);
}
}
protected void waitForBridgeView(int expected_size, long timeout, long interval, JChannel ... channels) {
long deadline=System.currentTimeMillis() + timeout;
while(System.currentTimeMillis() < deadline) {
boolean views_correct=true;
for(JChannel ch: channels) {
RELAY2 relay=ch.getProtocolStack().findProtocol(RELAY2.class);
View bridge_view=relay.getBridgeView(BRIDGE_CLUSTER);
if(bridge_view == null || bridge_view.size() != expected_size) {
views_correct=false;
break;
}
}
if(views_correct)
break;
Util.sleep(interval);
}
System.out.println("Bridge views:\n");
for(JChannel ch: channels) {
RELAY2 relay=ch.getProtocolStack().findProtocol(RELAY2.class);
View bridge_view=relay.getBridgeView(BRIDGE_CLUSTER);
System.out.println(ch.getAddress() + ": " + bridge_view);
}
for(JChannel ch: channels) {
RELAY2 relay=ch.getProtocolStack().findProtocol(RELAY2.class);
View bridge_view=relay.getBridgeView(BRIDGE_CLUSTER);
assert bridge_view != null && bridge_view.size() == expected_size
: ch.getAddress() + ": bridge view=" + bridge_view + ", expected=" + expected_size;
}
}
protected Route getRoute(JChannel ch, String site_name) {
RELAY2 relay=ch.getProtocolStack().findProtocol(RELAY2.class);
return relay.getRoute(site_name);
}
protected static class MyReceiver extends ReceiverAdapter {
protected final List<Integer> list=new ArrayList<>(5);
String chName;
MyReceiver(String chName) {
this.chName = chName;
}
public List<Integer> getList() {return list;}
public void clear() {list.clear();}
public void receive(Message msg) {
list.add(msg.getObject());
System.out.println(chName + "<-- " + msg.getObject());
}
}
}