package org.jgroups.tests; import org.jgroups.Global; import org.jgroups.JChannel; import org.jgroups.Message; import org.jgroups.ReceiverAdapter; import org.jgroups.blocks.MethodCall; import org.jgroups.blocks.RequestOptions; import org.jgroups.blocks.RpcDispatcher; import org.jgroups.logging.Log; import org.jgroups.logging.LogFactory; import org.jgroups.protocols.*; import org.jgroups.protocols.pbcast.GMS; import org.jgroups.protocols.pbcast.NAKACK2; import org.jgroups.stack.DiagnosticsHandler; import org.jgroups.stack.ProtocolStack; import org.jgroups.util.*; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import java.io.IOException; import java.lang.reflect.Method; import java.net.InetAddress; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; /** * Tests the {@link RSVP} protocol * @author Bela Ban */ @Test(groups=Global.FUNCTIONAL,singleThreaded=true) public class RSVPTest { protected static final int NUM=5; // number of members protected final JChannel[] channels=new JChannel[NUM]; protected final MyReceiver[] receivers=new MyReceiver[NUM]; protected MyDiagnosticsHandler handler; @BeforeMethod void setup() throws Exception { handler=new MyDiagnosticsHandler(InetAddress.getByName("224.0.75.75"), 7500, LogFactory.getLog(DiagnosticsHandler.class), new DefaultSocketFactory(), new DefaultThreadFactory("", false)); handler.start(); System.out.print("\nConnecting channels: "); for(int i=0; i < NUM; i++) { SHARED_LOOPBACK shared_loopback=new SHARED_LOOPBACK(); shared_loopback.setDiagnosticsHandler(handler); channels[i]=new JChannel(shared_loopback, new DISCARD(), new SHARED_LOOPBACK_PING(), new MERGE3().setValue("min_interval", 1000).setValue("max_interval", 3000), new NAKACK2().setValue("use_mcast_xmit", false) .setValue("discard_delivered_msgs", true) .setValue("log_discard_msgs", false).setValue("log_not_found_msgs", false) .setValue("xmit_table_num_rows", 5) .setValue("xmit_table_msgs_per_row", 10), new UNICAST3().setValue("xmit_table_num_rows", 5).setValue("xmit_interval", 300) .setValue("xmit_table_msgs_per_row", 10) .setValue("conn_expiry_timeout", 10000), new RSVP().setValue("timeout", 10000).setValue("throw_exception_on_timeout", false) .setValue("resend_interval", 500), new GMS().setValue("print_local_addr", false).setValue("join_timeout", 100) .setValue("leave_timeout", 100) .setValue("log_view_warnings", false) .setValue("view_ack_collection_timeout", 2000) .setValue("log_collect_msgs", false)); channels[i].setName(String.valueOf((i + 1))); receivers[i]=new MyReceiver(); channels[i].setReceiver(receivers[i]); channels[i].connect("RSVPTest"); System.out.print(i + 1 + " "); } Util.waitUntilAllChannelsHaveSameView(30000, 1000, channels); System.out.println(""); } @AfterMethod void tearDown() throws Exception { for(int i=NUM-1; i >= 0; i--) { ProtocolStack stack=channels[i].getProtocolStack(); String cluster_name=channels[i].getClusterName(); stack.stopStack(cluster_name); stack.destroy(); } handler.destroy(); } public void testSynchronousMulticastSend() throws Exception { for(JChannel ch: channels) assert ch.getView().size() == NUM : "channel " + ch.getAddress() + ": view is " + ch.getView(); // test with a multicast message: short value=(short)Math.abs((short)Util.random(10000)); Message msg=new Message(null, value); msg.setFlag(Message.Flag.RSVP); DISCARD discard=channels[0].getProtocolStack().findProtocol(DISCARD.class); discard.setDropDownMulticasts(1); long start=System.currentTimeMillis(); channels[0].send(msg); long diff=System.currentTimeMillis() - start; System.out.println("sending took " + diff + " ms"); int cnt=1; for(MyReceiver receiver: receivers) { System.out.println("receiver " + cnt++ + ": value=" + receiver.getValue()); } for(MyReceiver receiver: receivers) { long tmp_value=receiver.getValue(); assert tmp_value == value : "value is " + tmp_value + ", but should be " + value; } } public void testSynchronousUnicastSend() throws Exception { // test with a unicast message: short value=(short)Math.abs((short)Util.random(10000)); Message msg=new Message(channels[1].getAddress(), value).setFlag(Message.Flag.RSVP); DISCARD discard=channels[0].getProtocolStack().findProtocol(DISCARD.class); discard.setDropDownUnicasts(1); long start=System.currentTimeMillis(); channels[0].send(msg); long diff=System.currentTimeMillis() - start; System.out.println("sending took " + diff + " ms"); // UNICAST3 retransmission will resend the message *not* RSVP for(int i=0; i < 20; i++) { if(receivers[1].getValue() == value) break; Util.sleep(500); } long tmp_value=receivers[1].getValue(); assert tmp_value == value : "value is " + tmp_value + ", but should be " + value; } /** We block on an entry, but closing the channel cancels the task, so we return */ public void testCancellationByClosingChannel() throws Exception { // test with a multicast message: short value=(short)Math.abs((short)Util.random(10000)); Message msg=new Message(null, value).setFlag(Message.Flag.RSVP); DISCARD discard=channels[0].getProtocolStack().findProtocol(DISCARD.class); discard.setDiscardAll(true); RSVP rsvp=channels[0].getProtocolStack().findProtocol(RSVP.class); rsvp.setValue("throw_exception_on_timeout", true).setValue("timeout", 5000).setValue("resend_interval", 500); try { Thread closer=new Thread() { public void run() { Util.sleep(2000); System.out.println("closer closing channel"); channels[0].close(); } }; closer.start(); channels[0].send(msg); // this will be unsuccessful as the other 4 members won't receive it // test fails if we get a TimeoutException } finally { discard.setDiscardAll(false); rsvp.setValue("throw_exception_on_timeout", false); } } public String getGreeting() { // to be called via a remote RPC return "hello-" + (short)Util.random(1000); } public void testRpcWithFuture() throws Exception { final Method method=getClass().getMethod("getGreeting"); RpcDispatcher[] dispatchers=new RpcDispatcher[channels.length]; for(int i=0; i < dispatchers.length; i++) { channels[i].setReceiver(null); dispatchers[i]=new RpcDispatcher(channels[i], this); dispatchers[i].start(); } DISCARD discard=channels[0].getProtocolStack().findProtocol(DISCARD.class); discard.setDropDownMulticasts(1); RequestOptions opts=RequestOptions.SYNC().flags(Message.Flag.RSVP_NB); long start=System.currentTimeMillis(); Future<RspList<String>> future=dispatchers[0].callRemoteMethodsWithFuture(null, new MethodCall(method), opts); long rpc_time=System.currentTimeMillis() - start; start=System.currentTimeMillis(); RspList<String> rsps=future.get(3000, TimeUnit.MILLISECONDS); long get_time=System.currentTimeMillis() - start; System.out.printf("rsps=\n%s\nRPC time=%d ms, Get time=%d ms", rsps, rpc_time, get_time); assert rsps.size() == channels.length; for(Rsp rsp: rsps) assert rsp.wasReceived() && rsp.getValue() != null; assert rpc_time < 500; // take a GC into account } /** Tests that async RSVP tasks that are lost are removed after timeout ms */ public void testAsyncLostRSVPMessages() throws Exception { // test with a multicast message: short value=(short)Math.abs((short)Util.random(10000)); Message msg=new Message(null, value).setFlag(Message.Flag.RSVP_NB); DISCARD discard=channels[0].getProtocolStack().findProtocol(DISCARD.class); discard.setDiscardAll(true); RSVP rsvp=channels[0].getProtocolStack().findProtocol(RSVP.class); rsvp.setValue("timeout", 2000).setValue("resend_interval", 200); channels[0].send(msg); assert rsvp.getPendingRsvpRequests() == 1; for(int i=0; i < 10; i++) { if(rsvp.getPendingRsvpRequests() == 0) break; Util.sleep(1000); } assert rsvp.getPendingRsvpRequests() == 0; } protected static class MyReceiver extends ReceiverAdapter { short value=0; public short getValue() {return value;} public void receive(Message msg) {value=msg.getObject();} } protected static class MyDiagnosticsHandler extends DiagnosticsHandler { protected MyDiagnosticsHandler(InetAddress diagnostics_addr, int diagnostics_port, Log log, SocketFactory socket_factory, ThreadFactory thread_factory) { super(diagnostics_addr,diagnostics_port,log,socket_factory,thread_factory); } public void start() throws IOException {super.start();} public void stop() {} public void destroy() {super.stop();} } }