package com.limegroup.gnutella;
import java.net.InetAddress;
import junit.framework.Test;
import org.limewire.core.settings.ConnectionSettings;
import org.limewire.core.settings.FilterSettings;
import org.limewire.core.settings.SearchSettings;
import org.limewire.core.settings.UltrapeerSettings;
import org.limewire.util.MediaType;
import com.google.inject.AbstractModule;
import com.google.inject.Injector;
import com.google.inject.Stage;
import com.limegroup.gnutella.connection.RoutedConnection;
import com.limegroup.gnutella.messages.Message;
import com.limegroup.gnutella.messages.QueryRequest;
import com.limegroup.gnutella.routing.QueryRouteTable;
import com.limegroup.gnutella.xml.LimeXMLDocument;
/**
* Test to make sure that query routing tables are correctly exchanged between
* Ultrapeers.
*
* ULTRAPEER_1 ---- ULTRAPEER_2
*/
public final class UltrapeerQueryRouteTableTest extends ServerSideTestCase {
/**
* A filename that won't match.
*/
private static final String noMatch = "junkie junk";
private static final String match = "matchy match";
private ConnectionServices connectionServices;
private ConnectionManager connectionManager;
private SearchServices searchServices;
public UltrapeerQueryRouteTableTest(String name) {
super(name);
}
public static Test suite() {
return buildTestSuite(UltrapeerQueryRouteTableTest.class);
}
@Override
protected int getNumberOfUltrapeers() {
return 1;
}
@Override
protected int getNumberOfLeafpeers() {
return 0;
}
@Override
protected void setSettings() throws Exception {
ConnectionSettings.NUM_CONNECTIONS.setValue(4);
SearchSettings.GUESS_ENABLED.setValue(true);
UltrapeerSettings.DISABLE_ULTRAPEER_MODE.setValue(false);
UltrapeerSettings.EVER_ULTRAPEER_CAPABLE.setValue(true);
UltrapeerSettings.FORCE_ULTRAPEER_MODE.setValue(true);
ConnectionSettings.EVER_ACCEPTED_INCOMING.setValue(true);
ConnectionSettings.CONNECT_ON_STARTUP.setValue(false);
ConnectionSettings.LOCAL_IS_PRIVATE.setValue(false);
FilterSettings.BLACK_LISTED_IP_ADDRESSES.setValue(
new String[] {"*.*.*.*"});
FilterSettings.WHITE_LISTED_IP_ADDRESSES.setValue(
new String[] {"127.*.*.*",InetAddress.getLocalHost().getHostAddress()});
ConnectionSettings.WATCHDOG_ACTIVE.setValue(false);
ConnectionSettings.ALLOW_WHILE_DISCONNECTED.setValue(true);
// ConnectionSettings.PORT.setValue(6332);
UltrapeerSettings.NEED_MIN_CONNECT_TIME.setValue(false);
}
@Override
protected void setUpQRPTables() throws Exception {
QueryRouteTable qrt = new QueryRouteTable();
qrt.add(match);
for (Message m : qrt.encode(new QueryRouteTable()))
ULTRAPEER[0].send(m);
ULTRAPEER[0].flush();
}
@Override
public void setUp() throws Exception {
final ResponseVerifier testVerifier = new TestResponseVerifier();
Injector injector = LimeTestUtils.createInjector(Stage.PRODUCTION, new AbstractModule() {
@Override
protected void configure() {
bind(ResponseVerifier.class).toInstance(testVerifier);
}
});
super.setUp(injector);
connectionManager = injector.getInstance(ConnectionManager.class);
connectionServices = injector.getInstance(ConnectionServices.class);
searchServices = injector.getInstance(SearchServices.class);
int tries = 0;
do {
Thread.sleep(1000);
if (connectionServices.isConnected() &&
connectionManager.getInitializedConnections().isEmpty() &&
connectionManager.getInitializedConnections().get(0).getRoutedConnectionStatistics().getQueryRouteTablePercentFull() > 0)
break;
} while (tries++ < 10);
assertTrue(connectionServices.isConnected());
assertFalse(connectionManager.getInitializedConnections().isEmpty());
assertGreaterThan(0, connectionManager.getInitializedConnections().get(0).getRoutedConnectionStatistics().getQueryRouteTablePercentFull());
}
/**
* 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", connectionServices.isConnected());
searchServices.query(searchServices.newQueryGUID(), noMatch);
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.
QueryRequest qSent = BlockingConnectionUtils.getFirstInstanceOfMessageType(ULTRAPEER[0], QueryRequest.class);
assertEquals("wrong ttl", 2, qSent.getTTL());
assertEquals("wrong hops", 0, qSent.getHops());
}
/**
* 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", connectionServices.isConnected());
searchServices.query(searchServices.newQueryGUID(), match);
Thread.sleep(4000);
QueryRequest qSent = BlockingConnectionUtils.getFirstInstanceOfMessageType(ULTRAPEER[0], QueryRequest.class);
// 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.
if (qSent.getTTL() != 1) {
// see if qrp got exchanged properly
int num = connectionManager.getInitializedConnections().size();
double totalQrp = 0;
for (RoutedConnection rc : connectionManager.getInitializedClientConnections())
totalQrp += rc.getRoutedConnectionStatistics().getQueryRouteTablePercentFull();
fail("ttl was not 1 but "+qSent.getTTL()+" there were "+num+" connections with qrp total "+totalQrp);
}
assertEquals("wrong hops", 0, qSent.getHops());
}
private class TestResponseVerifier implements ResponseVerifier {
public boolean isMandragoreWorm(byte[] guid, Response response) {
return false;
}
public boolean matchesQuery(byte[] guid, Response response) {
return true;
}
public boolean matchesType(byte[] guid, Response response) {
return true;
}
public void record(QueryRequest qr, MediaType type) {
}
public void record(QueryRequest qr) {
}
public int score(String query, LimeXMLDocument richQuery, RemoteFileDesc response) {
return FilterSettings.MIN_MATCHING_WORDS.getValue() + 10 ;
}
}
}