package org.jgroups.tests;
import org.jgroups.Global;
import org.jgroups.JChannel;
import org.jgroups.ReceiverAdapter;
import org.jgroups.View;
import org.jgroups.protocols.*;
import org.jgroups.protocols.pbcast.GMS;
import org.jgroups.protocols.pbcast.NAKACK2;
import org.jgroups.protocols.pbcast.STABLE;
import org.jgroups.stack.GossipRouter;
import org.jgroups.stack.Protocol;
import org.jgroups.util.ResourceManager;
import org.jgroups.util.StackType;
import org.jgroups.util.Util;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author Bela Ban
*/
@Test(groups={Global.STACK_INDEPENDENT,Global.GOSSIP_ROUTER},sequential=true)
public class GossipRouterTest {
protected GossipRouter router;
protected JChannel a, b;
protected int gossip_router_port;
protected String gossip_router_hosts;
protected InetAddress bind_addr;
@BeforeClass
protected void setUp() throws Exception {
String tmp=Util.getProperty(Global.BIND_ADDR);
if(tmp == null) {
StackType type=Util.getIpStackType();
tmp=type == StackType.IPv6? "::1" : "127.0.0.1";
}
bind_addr=InetAddress.getByName(tmp);
gossip_router_port=ResourceManager.getNextTcpPort(bind_addr);
gossip_router_hosts=bind_addr.getHostAddress() + "[" + gossip_router_port + "]";
}
@AfterMethod (alwaysRun=true)
protected void tearDown() throws Exception {
if(router != null) {
router.stop();
router=null;
}
Util.close(b,a);
}
/**
* Tests the following scenario (http://jira.jboss.com/jira/browse/JGRP-682):
* - First node is started with tunnel.xml, cannot connect
* - Second node is started *with* GossipRouter
* - Now first node should be able to connect and first and second node should be able to merge into a group
* - SUCCESS: a view of 2
*/
@Test
public void testLateStart() throws Exception {
final Lock lock=new ReentrantLock();
final Condition cond=lock.newCondition();
AtomicBoolean done=new AtomicBoolean(false);
System.out.println("-- starting first channel");
a=createTunnelChannel("A");
a.setReceiver(new MyReceiver("c1", done, lock, cond));
a.connect("demo");
System.out.println("-- starting second channel");
b=createTunnelChannel("B");
b.setReceiver(new MyReceiver("c2", done, lock, cond));
b.connect("demo");
System.out.println("-- starting GossipRouter");
router=new GossipRouter(gossip_router_port, bind_addr.getHostAddress());
router.start();
System.out.println("-- waiting for merge to happen --");
long target_time=System.currentTimeMillis() + 40000;
lock.lock();
try {
while(System.currentTimeMillis() < target_time && done.get() == false) {
cond.await(1000, TimeUnit.MILLISECONDS);
}
}
finally {
lock.unlock();
}
Util.sleep(500);
View view=a.getView();
System.out.println("view=" + view);
assert view.size() == 2 : "view=" + view;
Util.close(b,a);
}
protected JChannel createTunnelChannel(String name) throws Exception {
return createTunnelChannel(name, true);
}
protected JChannel createTunnelChannel(String name, boolean include_failure_detection) throws Exception {
TUNNEL tunnel=(TUNNEL)new TUNNEL().setValue("enable_bundling",false).setValue("bind_addr", bind_addr);
tunnel.setGossipRouterHosts(gossip_router_hosts);
List<Protocol> protocols=new ArrayList<Protocol>();
protocols.addAll(Arrays.asList(tunnel,new PING(),new MERGE2().setValue("min_interval",1000).setValue("max_interval",3000)));
if(include_failure_detection)
protocols.addAll(Arrays.asList(new FD().setValue("timeout", 2000).setValue("max_tries", 2), new VERIFY_SUSPECT()));
protocols.addAll(Arrays.asList(new NAKACK2().setValue("use_mcast_xmit", false), new UNICAST(), new STABLE(), new GMS()));
JChannel ch=new JChannel(protocols);
if(name != null)
ch.setName(name);
return ch;
}
private static class MyReceiver extends ReceiverAdapter {
private final String name;
private final Lock lock;
private final AtomicBoolean done;
private final Condition cond;
public MyReceiver(String name, AtomicBoolean done, Lock lock, Condition cond) {
this.name=name;
this.done=done;
this.lock=lock;
this.cond=cond;
}
public void viewAccepted(View new_view) {
if(new_view.size() == 2) {
System.out.println("[" + name + "]: view=" + new_view);
lock.lock();
try {
done.set(true);
cond.signalAll();
}
finally {
lock.unlock();
}
}
}
}
}