package org.jgroups.tests;
import org.jgroups.*;
import org.jgroups.protocols.TP;
import org.jgroups.util.Promise;
import org.jgroups.util.Util;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
/**
* Tests unicasts to self (loopback of transport protocol)
* @author Richard Achmatowicz 12 May 2008
* @author Bela Ban Dec 31 2003
*/
@Test(groups=Global.STACK_DEPENDENT,sequential=true)
public class UnicastLoopbackTest extends ChannelTestBase {
JChannel channel=null;
@BeforeMethod
protected void setUp() throws Exception {
channel=createChannel(true, 1);
}
@AfterMethod
protected void tearDown() throws Exception {
Util.close(channel);
}
/**
* Tests that when UNICAST messages are sent with TP.loopback == true, the following conditions hold:
* (i) no messages touch the network
* (ii) all messages are correctly received
*
* @throws TimeoutException
*/
public void testUnicastMsgsWithLoopback() throws Exception {
final long TIMEOUT = 2 * 10000 ;
final int NUM=1000;
long num_msgs_sent_before = 0 ;
long num_msgs_sent_after = 0 ;
Promise<Boolean> p = new Promise<Boolean>() ;
MyReceiver receiver = new MyReceiver(NUM, p) ;
channel.setReceiver(receiver) ;
channel.connect("demo-group") ;
Address local_addr=channel.getAddress();
// set the loopback property on transport
setLoopbackProperty(channel, true) ;
num_msgs_sent_before = getNumMessagesSentViaNetwork(channel) ;
// send NUM UNICAST messages to ourself
for(int i=1; i <= NUM; i++) {
channel.send(new Message(local_addr, null, new Integer(i)));
if(i % 100 == 0)
System.out.println("-- sent " + i);
}
num_msgs_sent_after = getNumMessagesSentViaNetwork(channel) ;
// when loopback == true, messages should not touch the network
System.out.println("num msgs before: " + num_msgs_sent_before + ", num msgs after: " + num_msgs_sent_after);
assert num_msgs_sent_before <= num_msgs_sent_after;
assert num_msgs_sent_after < NUM/10;
try {
// wait for all messages to be received
p.getResultWithTimeout(TIMEOUT) ;
}
catch(TimeoutException te) {
// timeout exception occurred
Assert.fail("Test timed out before all messages were received") ;
}
}
/**
* Returns the number of messages sent across the network.
*
* @param ch
* @return the number of messages sent across the network
* @throws Exception
*/
private static long getNumMessagesSentViaNetwork(JChannel ch) throws Exception {
TP transport = ch.getProtocolStack().getTransport();
if (transport == null) {
throw new Exception("transport layer is not present - check default stack configuration") ;
}
return transport.getNumMessagesSent();
}
/**
* Set the value of the loopback property on the transport layer.
*
* @param ch
* @param loopback
* @throws Exception
*/
private static void setLoopbackProperty(JChannel ch, boolean loopback) throws Exception {
TP transport =ch.getProtocolStack().getTransport();
if (transport == null) {
throw new Exception("transport layer is not present - check default stack configuration") ;
}
// check if already set correctly
if ((loopback && transport.isLoopback()) || (!loopback && !transport.isLoopback()))
return ;
// otherwise, set it
transport.setLoopback(loopback);
}
/**
* A receiver which waits for all messages to be received and
* then sets a promise.
*/
private static class MyReceiver extends ReceiverAdapter {
private final int numExpected ;
private int numReceived;
private final Promise<Boolean> p ;
public MyReceiver(int numExpected, Promise<Boolean> p) {
this.numExpected = numExpected ;
this.numReceived = 0 ;
this.p = p ;
}
// when we receive a Message, we update the count of messages received
public void receive(Message msg) {
Integer num=(Integer)msg.getObject();
numReceived++;
if(num != null && num.intValue() % 100 == 0)
System.out.println("-- received " + num);
// if we have received NUM messages, set the result
if (numReceived >= numExpected)
p.setResult(Boolean.TRUE) ;
}
public int getNumMsgsReceived() {
return numReceived ;
}
}
}