package com.limegroup.gnutella;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import junit.framework.Test;
import com.limegroup.gnutella.messages.QueryRequest;
import com.limegroup.gnutella.search.HostData;
import com.limegroup.gnutella.settings.ConnectionSettings;
import com.limegroup.gnutella.settings.UltrapeerSettings;
import com.limegroup.gnutella.stubs.ActivityCallbackStub;
import com.limegroup.gnutella.util.BaseTestCase;
import com.limegroup.gnutella.util.PrivilegedAccessor;
import com.limegroup.gnutella.xml.MetaFileManager;
/**
* Test to make sure that query routing tables are correctly exchanged between
* Ultrapeers.
*
* ULTRAPEER_1 ---- ULTRAPEER_2
*/
public final class UltrapeerQueryRouteTableTest extends BaseTestCase {
private static ActivityCallback CALLBACK;
private static MetaFileManager FMAN;
private static TestMessageRouter MESSAGE_ROUTER;
private static RouterService ROUTER_SERVICE;
/**
* A filename that won't match.
*/
private static final String noMatch = "junkie junk";
/**
* The central Ultrapeer used in the test.
*/
//private static final RouterService ULTRAPEER_2 =
//new RouterService(new TestCallback());
//private static final ReplyHandler REPLY_HANDLER =
// new TestReplyHandler();
private static List REPLIES = new LinkedList();
private static List SENT = new LinkedList();
public UltrapeerQueryRouteTableTest(String name) {
super(name);
}
public static Test suite() {
return buildTestSuite(UltrapeerQueryRouteTableTest.class);
}
public static void main(String[] args) {
junit.textui.TestRunner.run(suite());
}
private static void setSettings() throws Exception {
setStandardSettings();
//SearchSettings.PROBE_TTL.setValue((byte)1);
ConnectionSettings.LOCAL_IS_PRIVATE.setValue(false);
ConnectionSettings.USE_GWEBCACHE.setValue(false);
ConnectionSettings.WATCHDOG_ACTIVE.setValue(false);
ConnectionSettings.ALLOW_WHILE_DISCONNECTED.setValue(true);
ConnectionSettings.PORT.setValue(6332);
UltrapeerSettings.NEED_MIN_CONNECT_TIME.setValue(false);
}
public static void globalSetUp() throws Exception {
setSettings();
launchBackend();
CALLBACK = new TestCallback();
FMAN = new MetaFileManager();
MESSAGE_ROUTER = new TestMessageRouter();
ROUTER_SERVICE = new RouterService(
CALLBACK, MESSAGE_ROUTER, FMAN);
ROUTER_SERVICE.start();
RouterService.connectToHostAsynchronously("localhost",
Backend.BACKEND_PORT);
// Wait for awhile after the connection to make sure the hosts have
// time to exchange QRP tables.
Thread.sleep(10 * 1000);
assertTrue("should be connected", RouterService.isConnected());
}
public void setUp() throws Exception {
setSettings();
REPLIES.clear();
SENT.clear();
}
public void tearDown() throws Exception {
}
/**
* Test to make sure we will never send with a TTL of 1 to a
* Ultrapeer that doesn't have a hit.
*/
public void testSentQueryIsNotTTL1() throws Exception {
assertTrue("should be connected", RouterService.isConnected());
QueryRequest qr = QueryRequest.createQuery(noMatch, (byte)1);
sendQuery(qr);
Thread.sleep(2000);
// we will send the query, but with a TTL of 2, not 1, because
// the ultrapeer doesn't have this query in its qrp table.
assertTrue("should have sent query", !SENT.isEmpty());
assertEquals("should not have received any replies", 0, REPLIES.size());
QueryRequest qSent = (QueryRequest)SENT.get(0);
assertEquals("wrong ttl", 2, qSent.getTTL());
assertEquals("wrong hops", 0, qSent.getHops());
assertEquals("wrong query", qr.getQuery(), qSent.getQuery());
assertEquals("wrong guid", qr.getGUID(), qSent.getGUID());
}
/**
* Test to make sure that dynamic querying sends a query with TTL=1 and
* other properties when a neighboring Ultrapeer has a hit in its QRP
* table for that query.
*/
public void testDynamicQueryingWithQRPHit() throws Exception {
assertTrue("should be connected", RouterService.isConnected());
QueryRequest qr = QueryRequest.createQuery(
"FileManagerTest.class." + Backend.SHARED_EXTENSION, (byte)1);
sendQuery(qr);
Thread.sleep(4000);
assertTrue("should have sent query", !SENT.isEmpty());
assertTrue("should have received replies", !REPLIES.isEmpty());
QueryRequest qSent = (QueryRequest)SENT.get(0);
// The TTL on the sent query should be 1 because the other Ultrapeer
// should have a "hit" in its QRP table. When there's a hit, we
// send with TTL 1 simply because it's likely that it's popular.
assertEquals("wrong ttl", 1, qSent.getTTL());
assertEquals("wrong hops", 0, qSent.getHops());
assertEquals("wrong query", qr.getQuery(), qSent.getQuery());
assertEquals("wrong guid", qr.getGUID(), qSent.getGUID());
}
/**
* The actual QueryRequest sent will not be the same (==) as this,
* because QueryHandler creates new queries with appropriate TTLs.
*/
private static void sendQuery(QueryRequest qr) throws Exception {
ResponseVerifier VERIFIER = (ResponseVerifier)PrivilegedAccessor.getValue(ROUTER_SERVICE, "VERIFIER");
VERIFIER.record(qr);
MessageRouter mr = RouterService.getMessageRouter();
mr.sendDynamicQuery(qr);
//mr.broadcastQueryRequest(qr);
}
private static class TestMessageRouter extends StandardMessageRouter {
public TestMessageRouter() {
super();
}
public boolean originateQuery(QueryRequest r, ManagedConnection c) {
SENT.add(r);
super.sendQueryRequest(r, c);
return true;
}
}
private static class TestCallback extends ActivityCallbackStub {
public void handleQueryResult(RemoteFileDesc rfd,
HostData hd,
Set locs) {
REPLIES.add(new Object());
}
}
}