package com.limegroup.gnutella;
import java.util.Iterator;
import java.util.List;
import junit.framework.Test;
import com.limegroup.gnutella.messages.Message;
import com.limegroup.gnutella.routing.QueryRouteTable;
import com.limegroup.gnutella.stubs.*;
import com.limegroup.gnutella.util.PrivilegedAccessor;
import com.limegroup.gnutella.util.BaseTestCase;
public class BusyLeafQRTUpdateTest extends BaseTestCase {
private ManagedConnectionCountQRT peer;
private ManagedConnectionCountQRT leaf;
private ConnectionManagerCountQRT cm;
private MessageRouter mr;
public static void globalSetUp() throws Exception {
new RouterService( new ActivityCallbackStub() );
}
public void setUp() throws Exception {
cm=new ConnectionManagerCountQRT();
peer=new ManagedConnectionCountQRT();
leaf=new ManagedConnectionCountQRT();
peer.setLeafConnection(false);
leaf.setLeafConnection(true);
cm.addStubOvrConnection(peer);
cm.addStubOvrConnection(leaf);
mr=RouterService.getMessageRouter();
PrivilegedAccessor.setValue( MessageRouter.class, "_manager", cm);
PrivilegedAccessor.setValue( MessageRouter.class, "_fileManager", new FileManagerStub() );
PrivilegedAccessor.setValue( RouterService.class, "manager", cm);
}
/**
* Start of BusyLeafQRTUpdateTest suite of tests
*
* @throws Exception
*/
public void testBusyLeafNoticed() throws Exception {
leaf.setBusyEnoughToTriggerQRTRemoval(true);
// Should't work for >TEST_MIN_BUSY_LEAF_TIME seconds
assertFalse( isAnyBusyLeafTriggeringQRTUpdate() );
waitForSeconds();
// Should work, since >TEST_MIN_BUSY_LEAF_TIME seconds have elapsed
assertTrue( isAnyBusyLeafTriggeringQRTUpdate() );
// UPDATE: Should still work, prior one should NOT have cleared the busy flag.
assertTrue( isAnyBusyLeafTriggeringQRTUpdate() );
}
public void testBusyPeerNotNoticed() throws Exception {
peer.setBusyEnoughToTriggerQRTRemoval(true);
// Should't work at all...
assertFalse( isAnyBusyLeafTriggeringQRTUpdate() );
waitForSeconds();
// Shouldn't work still
assertFalse( isAnyBusyLeafTriggeringQRTUpdate() );
}
public void testNonBusyLastHop() throws Exception {
// No busy leaves
forwardQueryRouteTablesCaller();
assertEquals( 1, getTotalNumberOfLeavesQRTsIncluded() );
cm.clearConnectionQRTStatus();
waitForSeconds();
// Still no busy leaves
forwardQueryRouteTablesCaller();
assertEquals( 1, getTotalNumberOfLeavesQRTsIncluded() );
}
public void testBusyLastHop() throws Exception {
// No busy leaves
forwardQueryRouteTablesCaller();
assertEquals( 1, getTotalNumberOfLeavesQRTsIncluded() );
cm.clearConnectionQRTStatus();
leaf.setBusyEnoughToTriggerQRTRemoval(true);
waitForSeconds();
// A busy leaf should have been noticed
forwardQueryRouteTablesCaller();
assertEquals( 0, getTotalNumberOfLeavesQRTsIncluded() );
}
public void forwardQueryRouteTablesCaller() throws Exception {
PrivilegedAccessor.invokeMethod(mr, "forwardQueryRouteTables", null );
}
/**
* Shortcut to waiting for awhile
*
*/
public void waitForSeconds() throws Exception {
Thread.sleep(5000 + (ManagedConnectionCountQRT.TEST_MIN_BUSY_LEAF_TIME+5));
}
/**
* Check to see how many leaves' tables would be included in the LastHop QRT
* @return number of leaf tables which would be included in a LastHop QRT
*/
private int getTotalNumberOfLeavesQRTsIncluded() {
int leaves=0;
Iterator it=cm.getInitializedClientConnections().iterator();
while( it.hasNext() ){
ManagedConnectionCountQRT mc=((ManagedConnectionCountQRT)it.next());
if( mc._qrtIncluded )
leaves++;
}
return leaves;
}
/**
* Loops through all managed connections and checks them for whether they have
* been a busy leaf long enough to trigger a last-hop QRT update.
*
* @return true iff the last-hop QRT tables should be updated early.
*/
public boolean isAnyBusyLeafTriggeringQRTUpdate(){
boolean busyLeaf=false;
List list=cm.getInitializedClientConnections();
Iterator it=list.iterator();
while( !busyLeaf && it.hasNext() )
// NOTE: don't remove the leaf's BUSY flag, since some peers may not have
// been updated yet due to timing quirks.
if( ((ManagedConnection)it.next()).isBusyEnoughToTriggerQRTRemoval() )
busyLeaf=true;
return busyLeaf;
}
/**
* The local stub for testing busy leaf QRT updating functionality
*
* Attaches ManagedConnectionStubs to this, and performs superclass related
* functionality on them
*
* Also, adds method clearConnectionQRTStatus(), which loops through connections
* and clears the per-connection flag which is used to indicate whether or not a
* connection's QRT table was included in the LastHop QRT.
*/
static class ConnectionManagerCountQRT extends ConnectionManagerStub {
public void addStubOvrConnection( ManagedConnectionCountQRT mcso ) throws Exception {
PrivilegedAccessor.invokeMethod(
this, "connectionInitializing",
new Object[] { mcso }, new Class[] { Connection.class } );
PrivilegedAccessor.invokeMethod(
this, "connectionInitialized",
new Object[] { mcso }, new Class[] { ManagedConnection.class } );
}
/**
* Loop through connections and clear each one's "QRT Included" flag
*/
public void clearConnectionQRTStatus() {
Iterator it=getConnections().iterator();
while( it.hasNext() ) {
ManagedConnectionCountQRT mc=((ManagedConnectionCountQRT)it.next());
if( mc._qrtIncluded ) {
mc._qrtIncluded=false;
}
}
}
}
/**
* The local stub for testing busy leaf connections
*/
static class ManagedConnectionCountQRT extends ManagedConnectionStub {
private static final long TEST_MIN_BUSY_LEAF_TIME=1000*5;
public ManagedConnectionCountQRT() {
try {
PrivilegedAccessor.setValue(ManagedConnection.class, "MIN_BUSY_LEAF_TIME", new Long(TEST_MIN_BUSY_LEAF_TIME));
PrivilegedAccessor.setValue(this, "hopsFlowMax", new Integer(-1));
} catch (Exception e) {
ErrorService.error( e );
}
}
private boolean isLeaf = false;
public long getNextQRPForwardTime() {
return 0l;
}
public void incrementNextQRPForwardTime(long curTime) {
}
public boolean isUltrapeerQueryRoutingConnection() {
return !isLeaf;
}
/**
* If I'm not a leaf then I'm an Ultrapeer! See also
* isClientSupernodeConnection()
*/
public boolean isSupernodeClientConnection() {
return isLeaf;
}
/**
* If I'm not a leaf then I'm an Ultrapeer! See also
* isSupernodeClientConnection()
*/
public boolean isClientSupernodeConnection() {
return isLeaf;
}
public boolean isQueryRoutingEnabled() {
return !isLeaf;
}
public void send(Message m) {}
public void setBusyEnoughToTriggerQRTRemoval( boolean busy ) throws Exception{
PrivilegedAccessor.setValue(this, "hopsFlowMax", new Integer( ((busy)?(0):(-1)) ) );
setBusy(busy);
}
public void setLeafConnection( boolean isLeaf ){
this.isLeaf = isLeaf;
}
public boolean _qrtIncluded=false;
public QueryRouteTable getQueryRouteTableReceived() {
_qrtIncluded = true;
return super.getQueryRouteTableReceived();
}
}
/**
* JUnit crap...
*/
public BusyLeafQRTUpdateTest(String name) {
super(name);
}
public static Test suite() {
return buildTestSuite(BusyLeafQRTUpdateTest.class);
}
}