package com.limegroup.gnutella;
import java.io.File;
import java.util.Iterator;
import java.util.Random;
import junit.framework.Test;
import com.limegroup.gnutella.messages.Message;
import com.limegroup.gnutella.messages.QueryReply;
import com.limegroup.gnutella.messages.QueryRequest;
import com.limegroup.gnutella.messages.vendor.MessagesSupportedVendorMessage;
import com.limegroup.gnutella.messages.vendor.QueryStatusResponse;
import com.limegroup.gnutella.routing.QueryRouteTable;
import com.limegroup.gnutella.routing.RouteTableMessage;
import com.limegroup.gnutella.settings.SharingSettings;
import com.limegroup.gnutella.stubs.ActivityCallbackStub;
/**
* Tests that an Ultrapeer correctly handle Probe queries. Essentially tests
* the following methods of MessageRouter: handleQueryRequestPossibleDuplicate
* and handleQueryRequest
*
* ULTRAPEER_1 ---- CENTRAL TEST ULTRAPEER ---- ULTRAPEER_2
* |
* |
* |
* LEAF
*/
public final class ServerSideLeafGuidedQueriesTest extends ServerSideTestCase {
private static int TIMEOUT = 300;
public ServerSideLeafGuidedQueriesTest(String name) {
super(name);
}
public static Test suite() {
return buildTestSuite(ServerSideLeafGuidedQueriesTest.class);
}
public static void main(String[] args) {
junit.textui.TestRunner.run(suite());
}
public static Integer numUPs() {
return new Integer(29);
}
public static Integer numLeaves() {
return new Integer(1);
}
public static ActivityCallback getActivityCallback() {
return new ActivityCallbackStub();
}
public static void setSettings() throws Exception {
setSharedDirectories(new File[0]);
}
public static void quickDrainAll() throws Exception {
drainAll(ULTRAPEER, TIMEOUT);
drainAll(LEAF, TIMEOUT);
}
public static void setUpQRPTables() throws Exception {
QueryRouteTable qrt = new QueryRouteTable();
qrt.add("berkeley");
qrt.add("susheel");
qrt.addIndivisible(HugeTestUtils.UNIQUE_SHA1.toString());
for (Iterator iter=qrt.encode(null).iterator(); iter.hasNext(); ) {
LEAF[0].send((RouteTableMessage)iter.next());
LEAF[0].flush();
}
// for Ultrapeers
for (int i = 0; i < ULTRAPEER.length; i++) {
qrt = new QueryRouteTable();
qrt.add("leehsus");
qrt.add("berkeley");
for (Iterator iter=qrt.encode(null).iterator(); iter.hasNext(); ) {
ULTRAPEER[i].send((RouteTableMessage)iter.next());
ULTRAPEER[i].flush();
}
}
}
// BEGIN TESTS
// ------------------------------------------------------
public void testConfirmSupport() throws Exception {
Message m = getFirstMessageOfType(LEAF[0],
MessagesSupportedVendorMessage.class);
assertNotNull(m);
MessagesSupportedVendorMessage msvm =
(MessagesSupportedVendorMessage)m;
assertGreaterThan(0, msvm.supportsLeafGuidance());
}
public void testLeafIsDone() throws Exception {
quickDrainAll();
// we want to make sure that the leaf correctly guides the queries to
// stop.
// send a query from the leaf
QueryRequest query = QueryRequest.createQuery("berkeley");
LEAF[0].send(query);
LEAF[0].flush();
// one or more of the UPs should get it....
Thread.sleep(3000);
QueryRequest nQuery = null;
for (int i = 0; (i < ULTRAPEER.length); i++)
if (nQuery == null)
nQuery = getFirstQueryRequest(ULTRAPEER[i], TIMEOUT);
assertTrue(nQuery != null);
// now tell the main UP that you have got enough results
QueryStatusResponse sResp =
new QueryStatusResponse(new GUID(query.getGUID()), 250);
LEAF[0].send(sResp);
LEAF[0].flush();
quickDrainAll();
// UPs should not get any more queries
Thread.sleep(3000);
nQuery = null;
for (int i = 0; (i < ULTRAPEER.length); i++) {
nQuery = getFirstQueryRequest(ULTRAPEER[i], TIMEOUT);
assertNull(nQuery);
}
}
public void testUPRoutedEnough() throws Exception {
quickDrainAll();
// we want to make sure that the UP stops the query when enough results
// have been routed
// send a query from the leaf
QueryRequest query = QueryRequest.createQuery("berkeley");
LEAF[0].send(query);
LEAF[0].flush();
// one or more of the UPs should get it....
Thread.sleep(3000);
QueryRequest nQuery = null;
for (int i = 0; (i < ULTRAPEER.length); i++) {
QueryRequest local = getFirstQueryRequest(ULTRAPEER[i], TIMEOUT);
if ((nQuery == null) && (local != null))
nQuery = local;
// send 10 results from this Ultrapeer....
for (int j = 0; (j < 10) && (local != null); j++)
routeResultsToUltrapeer(nQuery.getGUID(), ULTRAPEER[i]);
}
assertTrue(nQuery != null);
// UPs should get more queries
Thread.sleep(5000);
nQuery = null;
for (int i = 0; (i < ULTRAPEER.length); i++) {
QueryRequest local = getFirstQueryRequest(ULTRAPEER[i],
TIMEOUT*2);
if ((nQuery == null) && (local != null))
nQuery = local;
}
assertNotNull(nQuery);
// now send enough results, we shouldn't get no more queries yo
routeResultsToUltrapeers(query.getGUID(), 200);
quickDrainAll(); // do this to make sure no queries were sent while executing
// we shouldn't get no more queries yo
Thread.sleep(3000);
nQuery = null;
for (int i = 0; (i < ULTRAPEER.length); i++) {
nQuery = getFirstQueryRequest(ULTRAPEER[i], TIMEOUT);
assertNull(nQuery);
}
}
public void testUPRoutedMax() throws Exception {
quickDrainAll();
// we want to make sure that the UP stops the query when enough results
// have been routed AND the leaf still wants more
// send a query from the leaf
QueryRequest query = QueryRequest.createQuery("berkeley");
LEAF[0].send(query);
LEAF[0].flush();
// one or more of the UPs should get it....
Thread.sleep(3000);
QueryRequest nQuery = null;
for (int i = 0; (i < ULTRAPEER.length) && (nQuery == null); i++) {
QueryRequest local = getFirstQueryRequest(ULTRAPEER[i], TIMEOUT);
if ((nQuery == null) && (local != null))
nQuery = local;
// send 10 results from this Ultrapeer....
for (int j = 0; (j < 10) && (local != null); j++)
routeResultsToUltrapeer(nQuery.getGUID(), ULTRAPEER[i]);
}
assertTrue(nQuery != null);
// send a QueryStatus, but not one that will make the UP stop
QueryStatusResponse sResp =
new QueryStatusResponse(new GUID(query.getGUID()), 25);
LEAF[0].send(sResp);
LEAF[0].flush();
// UPs should get more queries
Thread.sleep(3000);
nQuery = null;
for (int i = 0; (i < ULTRAPEER.length) && (nQuery == null); i++) {
QueryRequest local = getFirstQueryRequest(ULTRAPEER[i], TIMEOUT);
if ((nQuery == null) && (local != null))
nQuery = local;
}
assertNotNull(nQuery);
// now send enough results, we shouldn't get no more queries yo
routeResultsToUltrapeers(query.getGUID(), 200);
quickDrainAll(); // do this to make sure no queries were sent while executing
// we shouldn't get no more queries yo
Thread.sleep(4000);
nQuery = null;
for (int i = 0; (i < ULTRAPEER.length); i++) {
nQuery = getFirstQueryRequest(ULTRAPEER[i], TIMEOUT);
assertNull(nQuery);
}
}
public void testLongLivedLeafGuidance() throws Exception {
quickDrainAll();
// we want to make sure that the UP stops the query when enough results
// have been routed AND the leaf still wants more
// send a query from the leaf
QueryRequest query = QueryRequest.createQuery("berkeley");
LEAF[0].send(query);
LEAF[0].flush();
// one or more of the UPs should get it....
Thread.sleep(3000);
QueryRequest nQuery = null;
for (int i = 0; (i < ULTRAPEER.length) && (nQuery == null); i++) {
QueryRequest local = getFirstQueryRequest(ULTRAPEER[i], TIMEOUT);
if ((nQuery == null) && (local != null))
nQuery = local;
}
assertTrue(nQuery != null);
// send a QueryStatus, but not one that will make the UP stop
QueryStatusResponse sResp =
new QueryStatusResponse(new GUID(query.getGUID()), 10);
LEAF[0].send(sResp);
LEAF[0].flush();
// UPs should get more queries
Thread.sleep(3000);
nQuery = null;
for (int i = 0; (i < ULTRAPEER.length) && (nQuery == null); i++) {
QueryRequest local = getFirstQueryRequest(ULTRAPEER[i], TIMEOUT);
if ((nQuery == null) && (local != null))
nQuery = local;
}
assertNotNull(nQuery);
// send a QueryStatus, but not one that will make the UP stop
sResp = new QueryStatusResponse(new GUID(query.getGUID()), 30);
LEAF[0].send(sResp);
LEAF[0].flush();
// UPs should get more queries
Thread.sleep(4000);
nQuery = null;
for (int i = 0; (i < ULTRAPEER.length) && (nQuery == null); i++) {
QueryRequest local = getFirstQueryRequest(ULTRAPEER[i], TIMEOUT);
if ((nQuery == null) && (local != null))
nQuery = local;
}
assertNotNull(nQuery);
// send a QueryStatus that will make UP stop
sResp = new QueryStatusResponse(new GUID(query.getGUID()), 50);
LEAF[0].send(sResp);
LEAF[0].flush();
quickDrainAll(); // do this to make sure no queries were sent while executing
// we shouldn't get no more queries yo
Thread.sleep(3000);
nQuery = null;
for (int i = 0; (i < ULTRAPEER.length); i++) {
nQuery = getFirstQueryRequest(ULTRAPEER[i], TIMEOUT);
assertNull(nQuery);
}
}
private void routeResultsToUltrapeers(byte[] guid, int numResults)
throws Exception {
Random rand = new Random();
for (int i = 0; i < numResults; i++) {
int index = rand.nextInt(ULTRAPEER.length);
routeResultsToUltrapeer(guid, ULTRAPEER[index]);
}
}
private void routeResultsToUltrapeer(byte[] guid, Connection source)
throws Exception {
byte[] ip = new byte[] {(byte)127, (byte)0, (byte)0, (byte)1};
byte[] clientGUID = GUID.makeGuid();
Response[] resp = new Response[] {new Response(0, 10, "berkeley")};
QueryReply reply = new QueryReply(guid, (byte)3, 6346, ip, 0, resp,
clientGUID, false);
source.send(reply);
source.flush();
}
}