package org.jgroups.blocks;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.jgroups.Address;
import org.jgroups.blocks.BasicConnectionTable.Connection;
import org.jgroups.stack.IpAddress;
import org.jgroups.util.Util;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.concurrent.*;
/**
* Tests ConnectionTable
* @author Bela Ban
* @version $Id: ConnectionTableTest.java,v 1.7.2.4 2009/07/15 15:07:42 rachmatowicz Exp $
*/
public class ConnectionTableTest extends TestCase {
private BasicConnectionTable ct1, ct2;
static String bind_addr_str=null;
static InetAddress bind_addr=null;
static byte[] data=new byte[]{'b', 'e', 'l', 'a'};
Address addr1, addr2;
// needed as OSs need not release ports immediately after a socket has closed
int port_range = 3 ;
final static int PORT1=7521, PORT2=8931;
static {
try {
bind_addr_str = System.getProperty("jgroups.bind_addr", "127.0.0.1") ;
bind_addr=InetAddress.getByName(bind_addr_str);
}
catch(UnknownHostException e) {
e.printStackTrace();
}
}
public ConnectionTableTest(String testName) {
super(testName);
}
protected void setUp() throws Exception {
super.setUp();
addr1=new IpAddress(bind_addr, PORT1);
addr2=new IpAddress(bind_addr, PORT2);
}
protected void tearDown() throws Exception {
if(ct2 != null) {
ct2.stop();
ct2=null;
}
if(ct1 != null) {
ct1.stop();
ct1=null;
}
super.tearDown();
}
/**
* A connects to B and B connects to A at the same time. This test makes sure we only have <em>one</em> connection,
* not two, e.g. a spurious connection. Tests http://jira.jboss.com/jira/browse/JGRP-549
*/
public void testConcurrentConnect() throws Exception {
Sender sender1, sender2;
CyclicBarrier barrier=new CyclicBarrier(3);
ct1=new ConnectionTable(bind_addr, PORT1);
ct1.start();
ct2=new ConnectionTable(bind_addr, PORT2);
ct2.start();
BasicConnectionTable.Receiver dummy=new BasicConnectionTable.Receiver() {
public void receive(Address sender, byte[] data, int offset, int length) {}
};
ct1.setReceiver(dummy);
ct2.setReceiver(dummy);
sender1=new Sender((ConnectionTable)ct1, barrier, addr2, 0);
sender2=new Sender((ConnectionTable)ct2, barrier, addr1, 0);
sender1.start(); sender2.start();
Util.sleep(100);
int num_conns;
System.out.println("ct1: " + ct1 + "ct2: " + ct2);
num_conns=ct1.getNumConnections();
assertEquals(0, num_conns);
num_conns=ct2.getNumConnections();
assertEquals(0, num_conns);
barrier.await(10000, TimeUnit.MILLISECONDS);
sender1.join();
sender2.join();
System.out.println("ct1: " + ct1 + "\nct2: " + ct2);
num_conns=ct1.getNumConnections();
assertEquals(1, num_conns);
num_conns=ct2.getNumConnections();
assertEquals(1, num_conns);
Util.sleep(500);
System.out.println("ct1: " + ct1 + "\nct2: " + ct2);
num_conns=ct1.getNumConnections();
assertEquals(1, num_conns);
num_conns=ct2.getNumConnections();
assertEquals(1, num_conns);
Connection connection = ct1.getConnection(addr2);
assertFalse("valid connection to peer",connection.isSocketClosed());
connection = ct2.getConnection(addr1);
assertFalse("valid connection to peer",connection.isSocketClosed());;
}
private static class Sender extends Thread {
final ConnectionTable conn_table;
final CyclicBarrier barrier;
final Address dest;
final long sleep_time;
public Sender(ConnectionTable conn_table, CyclicBarrier barrier, Address dest, long sleep_time) {
this.conn_table=conn_table;
this.barrier=barrier;
this.dest=dest;
this.sleep_time=sleep_time;
}
public void run() {
try {
barrier.await(10000, TimeUnit.MILLISECONDS);
if(sleep_time > 0)
Util.sleep(sleep_time);
conn_table.send(dest, data, 0, data.length);
}
catch(Exception e) {
}
}
}
public void testBlockingQueue() {
final BlockingQueue queue=new LinkedBlockingQueue();
Thread taker=new Thread() {
public void run() {
try {
System.out.println("taking an element from the queue");
queue.take();
System.out.println("clear");
}
catch(InterruptedException e) {
}
}
};
taker.start();
Util.sleep(500);
queue.clear(); // does this release the taker thread ?
Util.interruptAndWaitToDie(taker);
assertFalse("taker: " + taker, taker.isAlive());
}
public void testStopConnectionTableNoSendQueues() throws Exception {
ct1=new ConnectionTable(new DummyReceiver(), bind_addr, null, PORT1, PORT1+port_range, 60000, 120000);
ct1.setUseSendQueues(false);
ct1.start();
ct2=new ConnectionTable(new DummyReceiver(), bind_addr, null, PORT2, PORT2+port_range, 60000, 120000);
ct2.setUseSendQueues(false);
ct2.start();
_testStop(ct1, ct2);
}
public void testStopConnectionTableWithSendQueues() throws Exception {
ct1=new ConnectionTable(new DummyReceiver(), bind_addr, null, PORT1, PORT1+port_range, 60000, 120000);
ct1.start();
ct2=new ConnectionTable(new DummyReceiver(), bind_addr, null, PORT2, PORT2+port_range, 60000, 120000);
ct2.start();
_testStop(ct1, ct2);
}
public void testStopConnectionTableNIONoSendQueues() throws Exception {
ct1=new ConnectionTableNIO(new DummyReceiver(), bind_addr, null, PORT1, PORT1+port_range, 60000, 120000, false);
ct1.setUseSendQueues(false);
ct2=new ConnectionTableNIO(new DummyReceiver(), bind_addr, null, PORT2, PORT2+port_range, 60000, 120000, false);
ct2.setUseSendQueues(false);
ct1.start();
ct2.start();
_testStop(ct1, ct2);
}
public void testStopConnectionTableNIOWithSendQueues() throws Exception {
ct1=new ConnectionTableNIO(new DummyReceiver(), bind_addr, null, PORT1, PORT1+port_range, 60000, 120000, false);
ct2=new ConnectionTableNIO(new DummyReceiver(), bind_addr, null, PORT2, PORT2+port_range, 60000, 120000, false);
ct1.start();
ct2.start();
_testStop(ct1, ct2);
}
private void _testStop(BasicConnectionTable table1, BasicConnectionTable table2) throws Exception {
table1.send(addr1, data, 0, data.length); // send to self
assertEquals(0, table1.getNumConnections()); // sending to self should not create a connection
table1.send(addr2, data, 0, data.length); // send to other
table2.send(addr2, data, 0, data.length); // send to self
table2.send(addr1, data, 0, data.length); // send to other
System.out.println("table1:\n" + table1 + "\ntable2:\n" + table2);
assertEquals(1, table1.getNumConnections());
assertEquals(1, table2.getNumConnections());
table2.stop();
table1.stop();
assertEquals(0, table1.getNumConnections());
assertEquals(0, table2.getNumConnections());
}
public static Test suite() {
return new TestSuite(ConnectionTableTest.class);
}
public static void main(String[] args) {
junit.textui.TestRunner.run(ConnectionTableTest.suite());
}
static class DummyReceiver implements ConnectionTable.Receiver {
public void receive(Address sender, byte[] data, int offset, int length) {
System.out.println("-- received " + length + " bytes from " + sender);
}
}
static class DummyReceiverNIO implements ConnectionTableNIO.Receiver {
public void receive(Address sender, byte[] data, int offset, int length) {
System.out.println("-- received " + length + " bytes from " + sender);
}
}
}