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(); } }