package org.jgroups.tests;
import org.jgroups.*;
import org.jgroups.protocols.TP;
import org.jgroups.util.MessageBatch;
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;
import java.util.concurrent.TimeoutException;
/**
* Tests unicast and multicast messages to self (loopback of transport protocol)
* @author Richard Achmatowicz 12 May 2008
* @author Bela Ban Dec 31 2003
*/
@Test(groups=Global.STACK_DEPENDENT,singleThreaded=true)
public class LoopbackTest extends ChannelTestBase {
protected JChannel channel;
@BeforeMethod protected void setUp() throws Exception {channel=createChannel(true, 1).name("A");}
@AfterMethod protected void tearDown() throws Exception {Util.close(channel);}
/**
* Tests that when UNICAST messages are sent to self, the following conditions hold:
* (i) no messages touch the network
* (ii) all messages are correctly received
*/
public void testUnicastMsgsWithLoopback() throws Exception {
sendMessagesWithLoopback(true);
}
/**
* Tests that when MULTICAST messages are sent to self, the following conditions hold:
* (i) no messages touch the network
* (ii) all messages are correctly received
*/
public void testMulticastMsgsWithLoopback() throws Exception {
sendMessagesWithLoopback(false);
}
protected void sendMessagesWithLoopback(boolean unicast) throws Exception {
final long TIMEOUT = 60_0000;
final int NUM=1000;
long num_msgs_sent_before = 0;
long num_msgs_sent_after = 0;
Promise<Boolean> promise = new Promise<>() ;
MyReceiver receiver = new MyReceiver(NUM, promise) ;
channel.setReceiver(receiver) ;
channel.connect("UnicastLoopbackTest") ;
int largest_thread_pool_size=channel.getProtocolStack().getTransport().getThreadPoolSizeLargest();
num_msgs_sent_before = getNumMessagesSentViaNetwork(channel) ;
// send NUM messages to dest
Address dest=unicast? channel.getAddress() : null;
for(int i=1; i <= NUM; i++) {
channel.send(new Message(dest, i));
if(i % 100 == 0)
System.out.printf("-- [%s] sent %d\n", Thread.currentThread().getName(), i);
}
num_msgs_sent_after = getNumMessagesSentViaNetwork(channel) ;
System.out.printf("\nlargest pool size before: %d after: %d\n", largest_thread_pool_size,
largest_thread_pool_size=channel.getProtocolStack().getTransport().getThreadPoolSizeLargest());
// when sending msgs to self, 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;
if(unicast)
assert num_msgs_sent_after < NUM/10;
else
assert num_msgs_sent_after <= NUM; // max of NUM single messages; probably some batches were sent
try {
// wait for all messages to be received
promise.getResultWithTimeout(TIMEOUT) ;
}
catch(TimeoutException te) {
// timeout exception occurred
Assert.fail("Test timed out before all messages were received; received " + receiver.getNumMsgsReceived()) ;
}
}
/**
* 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();
}
/**
* 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=msg.getObject();
numReceived++;
if(num != null && num % 100 == 0)
System.out.printf("-- [%s] received %d\n", Thread.currentThread().getName(), num);
// if we have received NUM messages, set the result
if (numReceived >= numExpected)
p.setResult(Boolean.TRUE) ;
}
public void receive(MessageBatch batch) {
int size=batch.size();
numReceived+=size;
// System.out.printf("received batch of %d msgs, total: %d\n", size, numReceived);
for(Message msg: batch) {
Integer num=msg != null? msg.getObject() : null;
if(num != null && num % 100 == 0)
System.out.printf("-- [%s] received %d\n", Thread.currentThread().getName(), num);
}
if(numReceived >= numExpected)
p.setResult(Boolean.TRUE);
}
public int getNumMsgsReceived() {
return numReceived ;
}
}
}