package com.limegroup.gnutella.downloader; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Set; import junit.framework.Test; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.limewire.concurrent.ManagedThread; import org.limewire.core.settings.ConnectionSettings; import org.limewire.core.settings.SpeedConstants; import org.limewire.io.Connectable; import org.limewire.io.IpPort; import org.limewire.io.LocalSocketAddressProvider; import org.limewire.io.LocalSocketAddressProviderStub; import org.limewire.service.ErrorService; import org.limewire.util.PrivilegedAccessor; import com.limegroup.gnutella.Downloader.DownloadState; import com.limegroup.gnutella.RemoteFileDesc; import com.limegroup.gnutella.altlocs.AlternateLocation; import com.limegroup.gnutella.altlocs.AlternateLocationCollection; import com.limegroup.gnutella.altlocs.DirectAltLoc; import com.limegroup.gnutella.helpers.AlternateLocationHelper; import com.limegroup.gnutella.library.FileDesc; import com.limegroup.gnutella.library.IncompleteFileDesc; public class DownloadAltLocTest extends DownloadTestCase { private static final Log LOG = LogFactory.getLog(DownloadAltLocTest.class); public DownloadAltLocTest(String name) { super(name); } public static Test suite() { return buildTestSuite(DownloadAltLocTest.class); } @Override public void setUp() throws Exception { super.setUp(); // need some extra time for these tests setDownloadWaitTime(2 * 60 * 1000L); } public void testTwoAlternateLocations() throws Exception { LOG.info("-Testing Two AlternateLocations..."); final int RATE = 50; testUploaders[0].setRate(RATE); testUploaders[1].setRate(RATE); RemoteFileDesc rfd1= newRFDWithURN(PORTS[0], TestFile.hash().toString(), false); RemoteFileDesc rfd2= newRFDWithURN(PORTS[1], TestFile.hash().toString(), false); RemoteFileDesc[] rfds = {rfd1,rfd2}; tGeneric(rfds); //Prepare to check the alternate locations //Note: adiff should be blank List<AlternateLocation> alt1 = testUploaders[0].getIncomingGoodAltLocs(); List<AlternateLocation> alt2 = testUploaders[1].getIncomingGoodAltLocs(); AlternateLocation al1 = alternateLocationFactory.create(rfd1); AlternateLocation al2 = alternateLocationFactory.create(rfd2); assertTrue("uploader didn't recieve alt", !alt1.isEmpty()); assertTrue("uploader didn't recieve alt", !alt2.isEmpty()); assertTrue("uploader got wrong alt", !alt1.contains(al1)); assertEquals("incorrect number of locs ",1,alt1.size()); assertTrue("uploader got wrong alt", !alt2.contains(al2)); assertEquals("incorrect number of locs ",1,alt2.size()); AlternateLocation read1 = alt1.iterator().next(); AlternateLocation read2 = alt2.iterator().next(); assertInstanceof(DirectAltLoc.class, read1); assertInstanceof(DirectAltLoc.class, read2); IpPort ipp1 = ((DirectAltLoc)read1).getHost(); IpPort ipp2 = ((DirectAltLoc)read2).getHost(); if(ipp1 instanceof Connectable) assertFalse(((Connectable)ipp1).isTLSCapable()); if(ipp2 instanceof Connectable) assertFalse(((Connectable)ipp2).isTLSCapable()); } public void testUploaderAlternateLocations() throws Exception { // This is a modification of simple swarming based on alternate location // for the second swarm LOG.info("-Testing swarming from two sources one based on alt..."); //Throttle rate at 10KB/s to give opportunities for swarming. final int RATE=500; //The first uploader got a range of 0-100%. After the download receives //50%, it will close the socket. But the uploader will send some data //between the time it sent byte 50% and the time it receives the FIN //segment from the downloader. Half a second latency is tolerable. final int FUDGE_FACTOR=RATE*1024; testUploaders[0].setRate(RATE); testUploaders[1].setRate(RATE); RemoteFileDesc rfd1= newRFDWithURN(PORTS[0],TestFile.hash().toString(), false); RemoteFileDesc rfd2= newRFDWithURN(PORTS[1],TestFile.hash().toString(), false); RemoteFileDesc[] rfds = {rfd1}; //Prebuild an uploader alts in lieu of rdf2 AlternateLocationCollection<AlternateLocation> ualt = AlternateLocationCollection.create(rfd2.getSHA1Urn()); AlternateLocation al2 = alternateLocationFactory.create(rfd2); ualt.add(al2); testUploaders[0].setGoodAlternateLocations(ualt); tGeneric(rfds); //Make sure there weren't too many overlapping regions. int u1 = testUploaders[0].fullRequestsUploaded(); int u2 = testUploaders[1].fullRequestsUploaded(); LOG.debug("\tu1: "+u1+"\n"); LOG.debug("\tu2: "+u2+"\n"); LOG.debug("\tTotal: "+(u1+u2)+"\n"); //Note: The amount downloaded from each uploader will not //be equal, because the uploaders are stated at different times. assertLessThan("u1 did all the work", TestFile.length()/2+FUDGE_FACTOR, u1); assertLessThan("u2 did all the work", TestFile.length()/2+FUDGE_FACTOR, u2); } public void testAlternateLocationsAreRemoved() throws Exception { DOWNLOAD_WAIT_TIME = 2 * 60 * 1000; // This is a modification of simple swarming based on alternate location // for the second swarm LOG.info("-Testing swarming from two sources one based on alt..."); //Throttle rate at 10KB/s to give opportunities for swarming. final int RATE=5; // Make sure uploader2 will never complete an upload final int STOP_AFTER = 0; testUploaders[0].setRate(RATE); testUploaders[1].setRate(RATE); testUploaders[1].stopAfter(STOP_AFTER); testUploaders[2].setRate(RATE); RemoteFileDesc rfd1= newRFDWithURN(PORTS[0], TestFile.hash().toString(), false); RemoteFileDesc rfd2= newRFDWithURN(PORTS[1], TestFile.hash().toString(), false); RemoteFileDesc rfd3= newRFDWithURN(PORTS[2], TestFile.hash().toString(), false); RemoteFileDesc[] rfds = {rfd1}; //Prebuild an uploader alts in lieu of rdf2 AlternateLocationCollection<AlternateLocation> ualt = AlternateLocationCollection.create(rfd2.getSHA1Urn()); AlternateLocation al1 = alternateLocationFactory.create(rfd1); AlternateLocation al2 = alternateLocationFactory.create(rfd2); AlternateLocation al3 = alternateLocationFactory.create(rfd3); ualt.add(al2); ualt.add(al3); testUploaders[0].setGoodAlternateLocations(ualt); saveAltLocs = true; tGeneric(rfds); //Now let's check that the uploaders got the correct AltLocs. //Uploader 1: Must have al3. //Uploader 1 got correct Alts? List alts = testUploaders[0].getIncomingGoodAltLocs(); assertTrue(alts.contains(al3)); // al2 should have been sent to uploader1 as NAlt header assertTrue(testUploaders[0].getIncomingBadAltLocs().contains(al2)); // uploader3 should contain only al1 alts = testUploaders[2].getIncomingGoodAltLocs(); assertTrue(alts.contains(al1)); assertFalse(alts.contains(al2)); // Test Downloader has correct alts: the downloader should have // 2 or 3. If two they should be u1 and u3. If 3 u2 should be demoted assertTrue(validAlts.contains(al1)); assertTrue(validAlts.contains(al3)); Iterator iter = validAlts.iterator(); while(iter.hasNext()) { AlternateLocation loc = (AlternateLocation)iter.next(); if(loc.equals(al2)) assertTrue("failed loc not demoted",loc.isDemoted()); } // ManagedDownloader clears validAlts and invalidAlts after completion assertEquals(DownloadState.COMPLETE, managedDownloader.getState()); assertTrue(((Set)PrivilegedAccessor.getValue(managedDownloader, "validAlts")).isEmpty()); assertTrue(((Set)PrivilegedAccessor.getValue(managedDownloader, "invalidAlts")).isEmpty()); } public void testWeirdAlternateLocations() throws Exception { LOG.info("-Testing AlternateLocation weird..."); AlternateLocationHelper alternateLocationHelper = new AlternateLocationHelper(alternateLocationFactory); RemoteFileDesc rfd1=newRFDWithURN(PORTS[0],TestFile.hash().toString(), false); RemoteFileDesc[] rfds = {rfd1}; //Prebuild some uploader alts AlternateLocationCollection<AlternateLocation> ualt = AlternateLocationCollection.create( alternateLocationHelper.EQUAL_SHA1_LOCATIONS[0].getSHA1Urn()); ualt.add(alternateLocationHelper.EQUAL_SHA1_LOCATIONS[0]); ualt.add(alternateLocationHelper.EQUAL_SHA1_LOCATIONS[1]); ualt.add(alternateLocationHelper.EQUAL_SHA1_LOCATIONS[2]); ualt.add(alternateLocationHelper.EQUAL_SHA1_LOCATIONS[3]); testUploaders[0].setGoodAlternateLocations(ualt); saveAltLocs = true; tGeneric(rfds); //Check to check the alternate locations List alt1 = testUploaders[0].getIncomingGoodAltLocs(); assertEquals("uploader got bad alt locs",0,alt1.size()); AlternateLocation agood = alternateLocationFactory.create(rfd1); assertTrue(validAlts.contains(agood)); assertFalse(validAlts.contains(alternateLocationHelper.EQUAL_SHA1_LOCATIONS[0])); assertFalse(validAlts.contains(alternateLocationHelper.EQUAL_SHA1_LOCATIONS[1])); assertFalse(validAlts.contains(alternateLocationHelper.EQUAL_SHA1_LOCATIONS[2])); // ManagedDownloader clears validAlts and invalidAlts after completion assertEquals(DownloadState.COMPLETE, managedDownloader.getState()); assertTrue(((Set)PrivilegedAccessor.getValue(managedDownloader, "validAlts")).isEmpty()); assertTrue(((Set)PrivilegedAccessor.getValue(managedDownloader, "invalidAlts")).isEmpty()); } public void testAddSelfToMeshWithTree() throws Exception { LocalSocketAddressProviderStub localSocketAddressProvider = (LocalSocketAddressProviderStub) injector.getInstance(LocalSocketAddressProvider.class); localSocketAddressProvider.setLocalAddress(new byte[] { (byte)129, 0, 0, 1 }); localSocketAddressProvider.setLocalPort(6996); // change the minimum required bytes so it'll be added. HTTPDownloader.MIN_PARTIAL_FILE_BYTES = 1; networkManager.setAcceptedIncomingConnection(true); LOG.info("-Testing that downloader adds itself to the mesh if it has a tree"); int capacity=ConnectionSettings.CONNECTION_SPEED.getValue(); ConnectionSettings.CONNECTION_SPEED.setValue( SpeedConstants.MODEM_SPEED_INT); List u1Alt = testUploaders[0].getIncomingGoodAltLocs(); List u2Alt = testUploaders[1].getIncomingGoodAltLocs(); // neither uploader knows any alt locs. u1Alt.clear(); u2Alt.clear(); // the rate must be absurdly slow for the incomplete file.length() // check in HTTPDownloader to be updated. final int RATE=50; final int STOP_AFTER = ((TestFile.length()*2)/3)+1; testUploaders[0].setRate(RATE); testUploaders[0].stopAfter(STOP_AFTER); testUploaders[0].setSendThexTreeHeader(true); testUploaders[0].setSendThexTree(true); testUploaders[1].setRate(RATE); testUploaders[1].stopAfter(STOP_AFTER); RemoteFileDesc rfd1=newRFDWithURN(PORTS[0],TestFile.hash().toString(), false); RemoteFileDesc rfd2=newRFDWithURN(PORTS[1],TestFile.hash().toString(), false); RemoteFileDesc[] rfds = {rfd1,rfd2}; tGeneric(rfds); // make sure there was enough swarming opportunity int u1 = testUploaders[0].getRequestsReceived(); int u2 = testUploaders[1].getRequestsReceived(); // if not, start the test over. Worst case this hits the junit timeout. if (u1 < 5 || u2 < 5) { tearDown(); setUp(); testAddSelfToMeshWithTree(); return; } LOG.debug("\tu1: "+u1+"\n"); LOG.debug("\tu2: "+u2+"\n"); LOG.debug("\tTotal: "+(u1+u2)+"\n"); //both uploaders should know that this downloader is an alt loc. u1Alt = testUploaders[0].getIncomingGoodAltLocs(); u2Alt = testUploaders[1].getIncomingGoodAltLocs(); assertFalse(u1Alt.isEmpty()); assertFalse(u2Alt.isEmpty()); AlternateLocation al = alternateLocationFactory.create(TestFile.hash()); assertTrue(u1Alt.toString()+" should contain "+al+" u1: "+u1+" u2 "+u2, u1Alt.contains(al) ); assertTrue(u2Alt.toString()+" should contain "+al+" u1: "+u1+" u2 "+u2, u2Alt.contains(al) ); //Note: The amount downloaded from each uploader will not //be equal, because the uploaders are started at different times. assertLessThanOrEquals("u1 did too much work", STOP_AFTER, u1); assertGreaterThan("u2 did no work", 0, u2); ConnectionSettings.CONNECTION_SPEED.setValue(capacity); } public void testNotAddSelfToMeshIfNoTree() throws Exception { // change the minimum required bytes so it'll be added. PrivilegedAccessor.setValue(HTTPDownloader.class, "MIN_PARTIAL_FILE_BYTES", new Integer(1) ); PrivilegedAccessor.setValue(acceptor, "_acceptedIncoming", Boolean.TRUE ); LOG.info("-Testing that downloader does not add itself to the mesh if it has no tree"); int capacity=ConnectionSettings.CONNECTION_SPEED.getValue(); ConnectionSettings.CONNECTION_SPEED.setValue( SpeedConstants.MODEM_SPEED_INT); List u1Alt = testUploaders[0].getIncomingGoodAltLocs(); List u2Alt = testUploaders[1].getIncomingGoodAltLocs(); // neither uploader knows any alt locs. assertTrue(u1Alt.isEmpty()); assertTrue(u2Alt.isEmpty()); // the rate must be absurdly slow for the incomplete file.length() // check in HTTPDownloader to be updated. final int RATE=50; final int STOP_AFTER = TestFile.length()/2; testUploaders[0].setRate(RATE); testUploaders[0].stopAfter(STOP_AFTER); testUploaders[1].setRate(RATE); RemoteFileDesc rfd1=newRFDWithURN(PORTS[0],TestFile.hash().toString(), false); RemoteFileDesc rfd2=newRFDWithURN(PORTS[1],TestFile.hash().toString(), false); RemoteFileDesc[] rfds = {rfd1,rfd2}; tGeneric(rfds); //Make sure there weren't too many overlapping regions. int u1 = testUploaders[0].fullRequestsUploaded(); int u2 = testUploaders[1].fullRequestsUploaded(); LOG.debug("\tu1: "+u1+"\n"); LOG.debug("\tu2: "+u2+"\n"); LOG.debug("\tTotal: "+(u1+u2)+"\n"); //both uploaders should know that the other uploader is an alt loc. u1Alt = testUploaders[0].getIncomingGoodAltLocs(); u2Alt = testUploaders[1].getIncomingGoodAltLocs(); assertEquals(1,u1Alt.size()); assertEquals(1,u2Alt.size()); assertTrue(u1Alt.contains(alternateLocationFactory.create(rfd2))); assertTrue(u2Alt.contains(alternateLocationFactory.create(rfd1))); // but should not know about me. AlternateLocation al = alternateLocationFactory.create(TestFile.hash()); assertFalse( u1Alt.contains(al) ); assertFalse( u2Alt.contains(al) ); //Note: The amount downloaded from each uploader will not //be equal, because the uploaders are started at different times. assertLessThanOrEquals("u1 did too much work", STOP_AFTER, u1); assertGreaterThan("u2 did no work", 0, u2); ConnectionSettings.CONNECTION_SPEED.setValue(capacity); } public void testPartialAddsAltsActiveDownload() throws Exception { altBootstrapTest(false); } public void testPartialBootstrapsInactiveDownload() throws Exception { // this is different from testResumePartialWithAlternateLocations where the // download is resumed manuall altBootstrapTest(true); } private void altBootstrapTest(final boolean complete) throws Exception { LOG.info("-Testing a shared partial funnels alt locs to downloader"); int capacity=ConnectionSettings.CONNECTION_SPEED.getValue(); ConnectionSettings.CONNECTION_SPEED.setValue( SpeedConstants.MODEM_SPEED_INT); final int RATE=200; //second half of file + 1/8 of the file final int STOP_AFTER = TestFile.length()/10; testUploaders[0].setRate(RATE); testUploaders[0].stopAfter(STOP_AFTER); testUploaders[1].setRate(RATE); testUploaders[1].stopAfter(STOP_AFTER); testUploaders[2].setRate(RATE); final RemoteFileDesc rfd1=newRFDWithURN(PORTS[0], TestFile.hash().toString(), false); final RemoteFileDesc rfd2=newRFDWithURN(PORTS[1], TestFile.hash().toString(), false); final RemoteFileDesc rfd3=newRFDWithURN(PORTS[2], TestFile.hash().toString(), false); //Start with only RFD1. RemoteFileDesc[] rfds = {rfd1}; // Add RFD2 and 3 to the IncompleteFileDesc, make sure we use them. Thread locAdder = new ManagedThread( new Runnable() { public void run() { try { Thread.sleep(complete ? 4000 : 1500); FileDesc fd = library.getFileDescsMatching(TestFile.hash()).get(0); assertTrue(fd instanceof IncompleteFileDesc); altLocManager.add( alternateLocationFactory.create(rfd2),this); altLocManager.add( alternateLocationFactory.create(rfd3),this); } catch(Throwable e) { ErrorService.error(e); } } }); locAdder.start(); tGeneric(rfds); //Make sure there weren't too many overlapping regions. int u1 = testUploaders[0].getAmountUploaded(); int u2 = testUploaders[1].getAmountUploaded(); int u3 = testUploaders[2].getAmountUploaded(); LOG.debug("\tu1: "+u1+"\n"); LOG.debug("\tu2: "+u2+"\n"); LOG.debug("\tu3: "+u3+"\n"); LOG.debug("\tTotal: "+(u1+u2+u3)+"\n"); //Note: The amount downloaded from each uploader will not //be equal, because the uploaders are started at different times. assertEquals("u1 did too much work", STOP_AFTER, u1); assertEquals("u2 did too much work", STOP_AFTER, u2); assertGreaterThan("u3 did no work", 0, u3); ConnectionSettings.CONNECTION_SPEED.setValue(capacity); } /** * Test to make sure that we read the alternate locations from the * uploader response headers even if the response code is a 503, * try again later. */ public void testAlternateLocationsExchangedWithBusy() throws Exception { //tests that a downloader reads alternate locations from the //uploader even if it receives a 503 from the uploader. LOG.info("-Testing dloader gets alt from 503 uploader..."); //Throttle rate at 10KB/s to give opportunities for swarming. final int RATE=500; //The first uploader got a range of 0-100%. After the download receives //50%, it will close the socket. But the uploader will send some data //between the time it sent byte 50% and the time it receives the FIN //segment from the downloader. Half a second latency is tolerable. final int FUDGE_FACTOR=RATE*1024; testUploaders[0].setBusy(true); testUploaders[1].setRate(RATE); RemoteFileDesc rfd1=newRFDWithURN(PORTS[0], false); RemoteFileDesc rfd2=newRFDWithURN(PORTS[1], false); RemoteFileDesc[] rfds = {rfd1}; //Prebuild an uploader alts in lieu of rdf2 AlternateLocationCollection<AlternateLocation> ualt = AlternateLocationCollection.create(rfd1.getSHA1Urn()); AlternateLocation al2 = alternateLocationFactory.create(rfd2); ualt.add(al2); testUploaders[0].setGoodAlternateLocations(ualt); tGeneric(rfds); //Make sure there weren't too many overlapping regions. int u1 = testUploaders[0].fullRequestsUploaded(); int u2 = testUploaders[1].fullRequestsUploaded(); LOG.debug("\tu1: "+u1+"\n"); LOG.debug("\tu2: "+u2+"\n"); LOG.debug("\tTotal: "+(u1+u2)+"\n"); //Note: The amount downloaded from each uploader will not //be equal, because the uploaders are stated at different times. assertEquals("u1 did too much work", 0, u1); assertLessThan("u2 did all the work", TestFile.length()+FUDGE_FACTOR, u2); } public void testSimpleDownloadWithInitialAlts() throws Exception { LOG.info("-Testing download with initial alts"); //Throttle rate at 10KB/s to give opportunities for swarming. final int RATE=500; final int FUDGE_FACTOR=RATE*1024; testUploaders[0].setRate(RATE); testUploaders[1].setRate(RATE); RemoteFileDesc rfd1=newRFDWithURN(PORTS[0], false); RemoteFileDesc rfd2=newRFDWithURN(PORTS[1], false); RemoteFileDesc[] rfds1 = {rfd1}; List<RemoteFileDesc> rfds2 = new LinkedList<RemoteFileDesc>(); rfds2.add(rfd2); tGeneric(rfds1, rfds2); //Make sure there weren't too many overlapping regions. int u1 = testUploaders[0].fullRequestsUploaded(); int u2 = testUploaders[1].fullRequestsUploaded(); LOG.debug("\tu1: "+u1+"\n"); LOG.debug("\tu2: "+u2+"\n"); LOG.debug("\tTotal: "+(u1+u2)+"\n"); //Note: The amount downloaded from each uploader will not //be equal, because the uploaders are stated at different times. assertLessThan("u1 did all the work", TestFile.length()/2+FUDGE_FACTOR, u1); assertLessThan("u2 did all the work", TestFile.length()/2+FUDGE_FACTOR, u2); } }