package com.limegroup.gnutella.bootstrap;
import junit.framework.Test;
import com.limegroup.gnutella.Endpoint;
import com.limegroup.gnutella.HostCatcher;
import com.limegroup.gnutella.RouterService;
import com.limegroup.gnutella.settings.FilterSettings;
import com.limegroup.gnutella.stubs.ActivityCallbackStub;
import com.limegroup.gnutella.util.BaseTestCase;
import com.limegroup.gnutella.util.PrivilegedAccessor;
/**
* Unit tests for the HostCatcher/BootstrapServerManager interface.
*/
public class HostCatcherFetchTest extends BaseTestCase {
private HostCatcher hc;
private RecordingBootstrapServerManager gWebCache;
public HostCatcherFetchTest(String name) {
super(name);
}
public static Test suite() {
return buildTestSuite(HostCatcherFetchTest.class);
}
public static void main(String[] args) {
junit.textui.TestRunner.run(suite());
}
public void setUp() throws Exception {
FilterSettings.BLACK_LISTED_IP_ADDRESSES.setValue(new String[0]);
// we don't actually need the service, we just need it
// to start up the other services.
new RouterService( new ActivityCallbackStub() );
//Create special TestBootstrapServerManager to record GWebCache hits.
gWebCache=new RecordingBootstrapServerManager();
hc=new HostCatcher();
hc.initialize();
//Mutate HostCatcher to use this.
PrivilegedAccessor.setValue(hc, "gWebCache", gWebCache);
}
/** Indirectly checks that the GWebCache is hit when there is no
* gnutella.net file. */
public void testGetAnEndpoint_ImmediateFetch() throws Exception {
//Initially catcher is empty. Calling getAnEndpoint will block, so
//start thread to add a crap result.
assertEquals("initial hostfiles not empty.", 0, gWebCache.hostfiles);
//Now make sure that exactly one fetch was issued.
try {
interrupt(10);
assertNotNull("getAnEndpoint didn't return anything.", hc.getAnEndpoint());
fail("didn't get interrupted exception");
} catch(InterruptedException expected) {}
assertEquals("first look at hostfiles", 1, gWebCache.hostfiles);
// now add something to the hostCatcher and make sure
// it uses that instead of hitting the gWebCache for more.
hc.add( new Endpoint("1.1.1.2", 6346), false);
assertNotNull("getAnEndpoint didn't return anything.", hc.getAnEndpoint());
assertEquals("second look at hostfiles", 1, gWebCache.hostfiles);
// make sure we tell the scheduled fetcher it's okay to fetch again
hc.recoverHosts();
try {
interrupt(10);
assertNotNull("getAnEndpoint didn't return anything.", hc.getAnEndpoint());
fail("no exception");
} catch(InterruptedException expected) {}
assertEquals("third look at hostfiles", 2, gWebCache.hostfiles);
}
/** Indirectly checks that the GWebCache isn't initially hit when there is a
* gnutella.net file. */
public void testGetAnEndpoint_DelayedFetch() throws Exception {
//Fill up hc with crap pongs.
for (int i=0; i<20; i++)
hc.add(new Endpoint("1.1.1."+i, 6346+i), false);
//The first few calls (all those before GWEBCACHE_DELAY)
//will be forced to use the stale pongs...
//because it is bad to always hammer gWebCache's on startup
assertNotNull(hc.getAnEndpoint());
assertNotNull(hc.getAnEndpoint());
assertEquals(0, gWebCache.hostfiles);
//Make sure we use up all our endpoints before we
//hit a gwebcache, because it's always bad to hit a gwebcache
sleep(15 * 1000);
assertNotNull(hc.getAnEndpoint());
assertEquals(0, gWebCache.hostfiles);
assertNotNull(hc.getAnEndpoint());
assertEquals(0, gWebCache.hostfiles);
//Same after another few seconds.
sleep(15 * 1000);
assertNotNull(hc.getAnEndpoint());
assertEquals(0, gWebCache.hostfiles);
assertNotNull(hc.getAnEndpoint());
assertEquals(0, gWebCache.hostfiles);
//get the other endpoints.
for(int i = 6; i < 20; i++)
assertNotNull(hc.getAnEndpoint());
// now we should hit the gwebcache.
try {
hc.recoverHosts();
interrupt(10);
hc.getAnEndpoint();
fail("got an endpoint");
} catch(InterruptedException expected) {}
assertEquals(1, gWebCache.hostfiles);
}
private void interrupt(final int secs) {
final Thread thisThread = Thread.currentThread();
Thread responder=new Thread() {
public void run() {
// sleep & then interrupt the endpoint get.
try {
sleep(secs * 1000);
} catch(InterruptedException ignored) {}
thisThread.interrupt();
}
};
responder.start();
}
private void sleep(int msecs) throws Exception {
Thread.sleep(msecs);
}
}
/** Doesn't actually connect; just records HostCatcher's attempts. */
class RecordingBootstrapServerManager extends BootstrapServerManager {
int urlfiles=0;
int hostfiles=0;
int updates=0;
public RecordingBootstrapServerManager() {
super();
}
public synchronized void fetchBootstrapServersAsync() { urlfiles++; }
public synchronized int fetchEndpointsAsync() {
hostfiles++;
return FETCH_SCHEDULED;
}
public synchronized void sendUpdatesAsync(Endpoint myIP) { updates++; }
}