package com.limegroup.gnutella.search;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import junit.framework.Test;
import com.google.inject.AbstractModule;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.limegroup.gnutella.ConnectionManager;
import com.limegroup.gnutella.LimeTestUtils;
import com.limegroup.gnutella.ReplyHandler;
import com.limegroup.gnutella.connection.GnutellaConnection;
import com.limegroup.gnutella.messages.QueryRequest;
import com.limegroup.gnutella.messages.QueryRequestFactory;
import com.limegroup.gnutella.util.LimeTestCase;
import com.limegroup.gnutella.util.NewConnection;
import com.limegroup.gnutella.util.TestConnectionFactory;
import com.limegroup.gnutella.util.TestConnectionManager;
import com.limegroup.gnutella.util.TestResultCounter;
/**
* Tests the functionality of the <tt>QueryHandlerTest</tt> class.
*/
public final class QueryHandlerTest extends LimeTestCase {
private QueryRequestFactory queryRequestFactory;
private QueryHandlerFactory queryHandlerFactory;
private TestConnectionFactory testConnectionFactory;
public QueryHandlerTest(String name) {
super(name);
}
public static Test suite() {
return buildTestSuite(QueryHandlerTest.class);
}
public static void main(String[] args) {
junit.textui.TestRunner.run(suite());
}
private Injector createInjector(Module... modules) {
Injector injector = LimeTestUtils.createInjector(modules);
queryRequestFactory = injector.getInstance(QueryRequestFactory.class);
queryHandlerFactory = injector.getInstance(QueryHandlerFactory.class);
testConnectionFactory = injector.getInstance(TestConnectionFactory.class);
return injector;
}
/**
* Tests the method for sending an individual query to a
* single connections.
*/
public void testSendQueryToHost() throws Exception {
createInjector();
ReplyHandler rh = testConnectionFactory.createUltrapeerConnection();
QueryRequest query = queryRequestFactory.createQuery("test", (byte)1);
QueryHandlerImpl qh = (QueryHandlerImpl)queryHandlerFactory.createHandler(query, rh, new TestResultCounter());
GnutellaConnection mc = testConnectionFactory.createUltrapeerConnection();
qh.sendQueryToHost(query, mc);
List hostsQueried = qh.getQueriedConnections();
assertEquals("should not have added host", 0, hostsQueried.size());
// make sure we add the connection to the queries handlers
// if it doesn't support probe queries and the TTL is 1
qh.sendQueryToHost(query, testConnectionFactory.createLeafConnection(false));
hostsQueried = qh.getQueriedConnections();
assertEquals("should have added host", 1, hostsQueried.size());
// make sure it adds the connection when the ttl is higher
// than one and the connection supports probe queries
qh.sendQueryToHost(queryRequestFactory.createQuery("test"), testConnectionFactory.createUltrapeerConnection());
hostsQueried = qh.getQueriedConnections();
assertEquals("should have added host", 2, hostsQueried.size());
}
/**
* Tests the method for calculating the next TTL.
*/
public void testCalculateNewTTL() throws Exception {
byte ttl = QueryHandlerImpl.calculateNewTTL(2000, 15, (byte)5);
assertEquals("unexpected ttl", 3, ttl);
ttl = QueryHandlerImpl.calculateNewTTL(200, 15, (byte)5);
assertEquals("unexpected ttl", 2, ttl);
ttl = QueryHandlerImpl.calculateNewTTL(200000, 15, (byte)4);
assertEquals("unexpected ttl", 4, ttl);
ttl = QueryHandlerImpl.calculateNewTTL(20000, 5, (byte)2);
assertEquals("unexpected ttl", 2, ttl);
}
/**
* Tests the public sendQuery method to make sure it's working as
* expected.
*/
public void testPublicSendQuery() throws Exception {
Injector injector = createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(ConnectionManager.class).to(TestConnectionManager.class);
}
});
TestConnectionManager testConnectionManager = injector.getInstance(TestConnectionManager.class);
testConnectionManager.resetAndInitialize();
QueryHandler handler = queryHandlerFactory.createHandler(queryRequestFactory.createQuery("test"),
testConnectionFactory.createNewConnection(),
new TestResultCounter(0));
assertTrue(testConnectionManager.getInitializedConnections().size() > 0);
handler.sendQuery();
int numQueries = testConnectionManager.getNumUltrapeerQueries();
assertEquals("unexpected number of probe queries sent", 3, numQueries);
// these calls should not go through, as it's too soon after the probe
// was sent!
handler.sendQuery();
handler.sendQuery();
handler.sendQuery();
assertEquals("unexpected number of probe queries sent", 3,
testConnectionManager.getNumUltrapeerQueries());
Thread.sleep(8000);
handler.sendQuery();
Thread.sleep(1000);
// after the sleep, it should go through!
assertEquals("unexpected number of queries sent", 4, testConnectionManager.getNumUltrapeerQueries());
// these calls should not go through, as it's too soon after the last query
// was sent!
handler.sendQuery();
handler.sendQuery();
handler.sendQuery();
assertEquals("unexpected number of queries sent", 4, testConnectionManager.getNumUltrapeerQueries());
Thread.sleep(8000);
handler.sendQuery();
// after the sleep, it should go through!
assertEquals("unexpected number of queries sent", 5, testConnectionManager.getNumUltrapeerQueries());
// now, send out a bunch of queries to make sure that, eventually,
// new queries don't go out because we've reached too high a theoretical
// horizon. These queries aren't returning any results, so the TTLs
// should be relatively high, causing us to hit the theoretical
// horizon limit!
for(int i=0; i<testConnectionManager.getInitializedConnections().size()-2; i++) {
Thread.sleep(2000);
handler.sendQuery();
}
assertTrue("too many hosts queried! -- theoretical horizon too high",
(testConnectionManager.getNumUltrapeerQueries() <= 12));
}
/**
* Test to make sure that the theoretical horizon we've reached
* is being calculated correctly.
*/
public void testCalculateNewHosts() throws Exception {
createInjector();
// test for a degree 19, ttl 4 network
GnutellaConnection mc = testConnectionFactory.createNewConnection(19);
int horizon = 0;
for(int i=0; i<19; i++) {
horizon += QueryHandlerImpl.calculateNewHosts(mc, (byte)4);
}
assertEquals("incorrect horizon", 117325, horizon);
// test for a degree 30, ttl 3 network
mc = testConnectionFactory.createNewConnection(30);
horizon = 0;
for(int i=0; i<30; i++) {
horizon += QueryHandlerImpl.calculateNewHosts(mc, (byte)3);
}
assertEquals("incorrect horizon", 26130, horizon);
}
/**
* Tests the private method for sending queries to make sure the
* basics of query dispatching are working correctly.
*/
public void testPrivateSendQuery() throws Exception {
createInjector();
int numConnections = 15;
List<NewConnection> connections = new ArrayList<NewConnection>();
for(int i=0; i<numConnections; i++) {
connections.add(testConnectionFactory.createNewConnection(10));
}
QueryHandler handler = queryHandlerFactory.createHandler(queryRequestFactory.createQuery("test"),
testConnectionFactory.createNewConnection(8),
new TestResultCounter(0));
// just send queries to all connections
for(int i=0; i<numConnections; i++) {
((QueryHandlerImpl)handler).sendQuery(connections);
}
// just make sure all of the connections received the query
Iterator<NewConnection> iter = connections.iterator();
while(iter.hasNext()) {
NewConnection tc = iter.next();
assertTrue("should have received the query", tc.receivedQuery());
}
}
}