package com.limegroup.gnutella.downloader;
import junit.framework.Test;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.limewire.core.settings.ConnectionSettings;
import org.limewire.core.settings.ContentSettings;
import org.limewire.core.settings.DownloadSettings;
import org.limewire.core.settings.SpeedConstants;
import com.limegroup.gnutella.Downloader;
import com.limegroup.gnutella.RemoteFileDesc;
import com.limegroup.gnutella.Downloader.DownloadState;
import com.limegroup.gnutella.messages.vendor.ContentResponse;
/**
* Comprehensive test of downloads -- one of the most important tests in
* LimeWire.
*/
public class DownloadTest extends DownloadTestCase {
private static final Log LOG = LogFactory.getLog(DownloadTest.class);
public DownloadTest(String name) {
super(name);
}
public static Test suite() {
return buildTestSuite(DownloadTest.class);
}
public static void main(String[] args) {
junit.textui.TestRunner.run(suite());
}
/**
* Tests a basic download that does not swarm.
*/
public void testSimpleDownload10() throws Exception {
LOG.info("-Testing non-swarmed download...");
RemoteFileDesc rfd=newRFD(PORTS[0], false);
RemoteFileDesc[] rfds = {rfd};
tGeneric(rfds);
}
public void testSimpleDownload11() throws Exception {
LOG.info("-Testing non-swarmed download...");
RemoteFileDesc rfd=newRFDWithURN(PORTS[0], false);
RemoteFileDesc[] rfds = {rfd};
tGeneric(rfds);
}
public void testSimpleSwarm() throws Exception {
LOG.info("-Testing swarming from two sources...");
//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], false);
RemoteFileDesc rfd2=newRFDWithURN(PORTS[1], 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");
//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 testUnbalancedSwarm() throws Exception {
LOG.info("-Testing swarming from two unbalanced sources...");
final int RATE=500;
final int FUDGE_FACTOR=RATE*1024;
testUploaders[0].setRate(RATE);
testUploaders[1].setRate(RATE/10);
RemoteFileDesc rfd1=newRFDWithURN(PORTS[0], false);
RemoteFileDesc rfd2=newRFDWithURN(PORTS[1], 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();
//Note: The amount downloaded from each uploader will not
//be equal, because the uploaders are stated at different times.
LOG.debug("\tu1: "+u1+"\n");
LOG.debug("\tu2: "+u2+"\n");
LOG.debug("\tTotal: "+(u1+u2)+"\n");
assertLessThan("u1 did all the work", 9*TestFile.length()/10+FUDGE_FACTOR*10, u1);
assertLessThan("u2 did all the work", TestFile.length()/10+FUDGE_FACTOR, u2);
}
public void testSwarmWithInterrupt() throws Exception {
LOG.info("-Testing swarming from two sources (one broken)...");
final int RATE=100;
final int STOP_AFTER = TestFile.length()/4;
testUploaders[0].setRate(RATE);
testUploaders[1].setRate(RATE);
testUploaders[1].stopAfter(STOP_AFTER);
RemoteFileDesc rfd1=newRFDWithURN(PORTS[0], false);
RemoteFileDesc rfd2=newRFDWithURN(PORTS[1], false);
// Download first from rfd2 so we get its stall
// and then add in rfd1.
tGeneric(new RemoteFileDesc[] { rfd2 },
new RemoteFileDesc[] { rfd1 });
//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.
assertLessThanOrEquals("u2 did too much work", STOP_AFTER, u2);
assertGreaterThan(0,u2);
}
/**
* tests a swarm from a 1.0 and 1.1 source - designed to test stealing.
*/
public void testSwarmWithTheft() throws Exception {
LOG.info("-Testing swarming from two sources, one 1.0 and one 1.1");
//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=newRFD(PORTS[0], false);
RemoteFileDesc rfd2=newRFDWithURN(PORTS[1], 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");
//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 testAddDownload() throws Exception {
LOG.info("-Testing addDownload (increases 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);
Downloader download=null;
//Start one location, wait a bit, then add another.
download=downloadServices.download(new RemoteFileDesc[] {rfd1}, false, null);
((ManagedDownloader)download).addDownload(rfd2,true);
waitForComplete();
if (isComplete())
LOG.debug("pass"+"\n");
else
fail("FAILED: complete corrupt");
//Make sure there weren't too many overlapping regions. Each upload
//should do roughly half the work.
int u1 = testUploaders[0].fullRequestsUploaded();
int u2 = testUploaders[1].fullRequestsUploaded();
//Note: The amount downloaded from each uploader will not
//be equal, because the uploaders are stated at different times.
LOG.debug("\tu1: "+u1+"\n");
LOG.debug("\tu2: "+u2+"\n");
LOG.debug("\tTotal: "+(u1+u2)+"\n");
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 testStallingUploaderReplaced() throws Exception {
LOG.info("-Testing download completion with stalling downloader...");
//Throttle rate at 100KB/s to give opportunities for swarming.
final int RATE=100;
testUploaders[0].setRate(0.1f);//stalling uploader
testUploaders[1].setRate(RATE);
RemoteFileDesc rfd1=newRFDWithURN(PORTS[0], false);
RemoteFileDesc rfd2=newRFDWithURN(PORTS[1], false);
RemoteFileDesc[] rfds = {rfd1};
ManagedDownloader downloader = (ManagedDownloader)
downloadServices.download(rfds,RemoteFileDesc.EMPTY_LIST, null, false);
Thread.sleep(DownloadSettings.WORKER_INTERVAL.getValue()+1000);
downloader.addDownload(rfd2,false);
waitForComplete();
//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
LOG.debug("passed"+"\n");//file downloaded? passed
}
public void testStallingHeaderUploader() throws Exception {
LOG.info("-Testing download completion with stalling downloader...");
//Throttle rate at 100KB/s to give opportunities for swarming.
final int RATE=300;
testUploaders[0].setStallHeaders(true); //stalling uploader
testUploaders[1].setRate(RATE);
RemoteFileDesc rfd1=newRFDWithURN(PORTS[0], false);
RemoteFileDesc rfd2=newRFDWithURN(PORTS[1], false);
RemoteFileDesc[] rfds = {rfd1};
ManagedDownloader downloader = (ManagedDownloader)
downloadServices.download(rfds,RemoteFileDesc.EMPTY_LIST, null, false);
Thread.sleep(DownloadSettings.WORKER_INTERVAL.getValue()/2);
downloader.addDownload(rfd2,false);
waitForComplete();
// the stalled uploader should not have uploaded anything
assertEquals(0,testUploaders[0].getAmountUploaded());
LOG.debug("passed"+"\n");//file downloaded? passed
}
public void testAcceptableSpeedStallIsReplaced() throws Exception {
LOG.info("-Testing a download that is an acceptable speed but slower" +
" is replaced by another download that is faster");
final int SLOW_RATE = 5;
final int FAST_RATE = 50;
testUploaders[0].setRate(SLOW_RATE);
testUploaders[1].setRate(FAST_RATE);
RemoteFileDesc rfd1=newRFDWithURN(PORTS[0], false);
RemoteFileDesc rfd2=newRFDWithURN(PORTS[1], false);
RemoteFileDesc[] rfds = {rfd1,rfd2};
tGeneric(rfds);
Thread.sleep(8000);
int u1 = testUploaders[0].fullRequestsUploaded();
int u2 = testUploaders[1].fullRequestsUploaded();
int c1 = testUploaders[0].getConnections();
int c2 = testUploaders[1].getConnections();
assertEquals("u1 served full request", 0, u1);
assertGreaterThan("u1 didn't upload anything",0,testUploaders[0].getAmountUploaded());
assertGreaterThan("u2 not used", 0, u2);
assertEquals("extra connection attempts", 1, c1);
assertEquals("extra connection attempts", 1, c2);
assertTrue("slower uploader not replaced",testUploaders[0].getKilledByDownloader());
assertFalse("faster uploader killed",testUploaders[1].getKilledByDownloader());
}
public void testUploaderLowHigherRange() throws Exception {
LOG.info("-Testing that a download can handle an uploader giving low+higher ranges");
testUploaders[0].setRate(25);
testUploaders[0].setLowChunkOffset(50);
testUploaders[4].setRate(100); // control, to finish the test.
RemoteFileDesc rfd5 = newRFDWithURN(PORTS[4], false);
RemoteFileDesc rfd1 = newRFDWithURN(PORTS[0], false);
RemoteFileDesc[] rfds = {rfd1};
ManagedDownloaderImpl md = (ManagedDownloaderImpl)
downloadServices.download(rfds,true,null);
Thread.sleep(5000);
// at this point we should stall since we'll never get our 50 bytes
md.addDownloadForced(rfd5,false);
waitForComplete();
assertGreaterThanOrEquals(50,testUploaders[4].fullRequestsUploaded());
assertGreaterThanOrEquals(100000-50,testUploaders[0].fullRequestsUploaded());
}
public void testUploaderLowLowerRange() throws Exception {
LOG.info("-Testing that a download can handle an uploader giving low+lower ranges");
testUploaders[0].setRate(25);
testUploaders[0].setLowChunkOffset(-10);
testUploaders[4].setRate(100); // control, to finish the test.
RemoteFileDesc rfd1 = newRFDWithURN(PORTS[0], false);
RemoteFileDesc rfd5 = newRFDWithURN(PORTS[4], false);
RemoteFileDesc[] rfds = {rfd1};
ManagedDownloaderImpl md = (ManagedDownloaderImpl)
downloadServices.download(rfds,true,null);
Thread.sleep(5000);
md.addDownloadForced(rfd5,false);
// the first downloader should have failed after downloading a complete chunk
assertLessThan(100001,testUploaders[0].fullRequestsUploaded());
waitForComplete();
}
public void testUploaderHighHigherRange() throws Exception {
LOG.info("-Testing that a download can handle an uploader giving high+higher ranges");
testUploaders[0].setRate(25);
testUploaders[0].setHighChunkOffset(50);
testUploaders[4].setRate(100); // control, to finish the test.
RemoteFileDesc rfd1 = newRFDWithURN(PORTS[0], false);
RemoteFileDesc rfd5 = newRFDWithURN(PORTS[4], false);
RemoteFileDesc[] rfds = {rfd1};
ManagedDownloaderImpl md = (ManagedDownloaderImpl)
downloadServices.download(rfds,true,null);
Thread.sleep(5000);
md.addDownloadForced(rfd5,false);
// the first downloader should have failed without downloading a complete chunk
assertEquals(0,testUploaders[0].fullRequestsUploaded());
waitForComplete();
}
public void testUploaderHighLowerRange() throws Exception {
LOG.info("-Testing that a download can handle an uploader giving high+lower ranges");
testUploaders[0].setRate(25);
testUploaders[0].setHighChunkOffset(-10);
testUploaders[4].setRate(100); // control, to finish the test.
RemoteFileDesc rfd5 = newRFDWithURN(PORTS[4], false);
RemoteFileDesc rfd1 = newRFDWithURN(PORTS[0], false);
RemoteFileDesc[] rfds = {rfd1};
ManagedDownloaderImpl md = (ManagedDownloaderImpl)
downloadServices.download(rfds,true,null);
Thread.sleep(5000);
// at this point we should stall since we'll never get our 10 bytes
md.addDownloadForced(rfd5,false);
waitForComplete();
assertGreaterThanOrEquals(50,testUploaders[4].fullRequestsUploaded());
assertGreaterThanOrEquals(100000-50,testUploaders[0].fullRequestsUploaded());
}
public void testBusyHostIsUsed() throws Exception {
setDownloadWaitTime(2 * DEFAULT_WAIT_TIME);
LOG.info("-Testing a once-busy host is reused.");
//Throttle rate to give opportunities for swarming.
final int SLOW_RATE=5;
final int FAST_RATE=100;
testUploaders[0].setBusy(true);
testUploaders[0].setTimesBusy(1);
testUploaders[0].setRate(FAST_RATE);
testUploaders[1].setRate(SLOW_RATE);
RemoteFileDesc rfd1=newRFDWithURN(PORTS[0], false);
RemoteFileDesc rfd2=newRFDWithURN(PORTS[1], false);
RemoteFileDesc[] rfds = {rfd1}; // see note below about why only rfd1
// Interesting odd factoid about the test:
// Whether or not RFD1 or RFD2 is tried first is a BIG DEAL.
// This test is making sure that RFD1 is reused even though
// RFD2 is actively downloading. However, because ManagedDownloader
// sets the RetryAfter time differently depending on if
// someone is already downloading (and this test will fail
// if it sets the time to be the longer 10 minute wait),
// we must ensure that RFD1 is tried first, so the wait
// is only set to 1 minute.
ManagedDownloader download= (ManagedDownloader) downloadServices.download(rfds, RemoteFileDesc.EMPTY_LIST, null, false);
Thread.sleep(DownloadSettings.WORKER_INTERVAL.getValue()+1000);
download.addDownload(rfd2,true);
waitForComplete();
int u1 = testUploaders[0].getAmountUploaded();
int u2 = testUploaders[1].getAmountUploaded();
LOG.debug("u1: " + u1);
LOG.debug("u2: " + u2);
assertGreaterThan("u1 did no work", 0, u1);
assertGreaterThan("u2 did no work", 0, u2);
// This should ideally be an equals ( not >= ) but timing
// conditions can cause assignGrey to fail too early,
// causing more connection attempts.
assertGreaterThanOrEquals("wrong connection attempts",
2, testUploaders[0].getConnections());
assertEquals("wrong connection attempts",
1, testUploaders[1].getConnections());
}
/**
* Tests that if the downloader has two sources, adding a third does not
* cause it to drop either of the others -- important to test since we have
* added logic that tries to knock off queued download and replace with good
* downloaders
*/
public void testFullSwarmDownloadsNotDropped() throws Exception {
LOG.info("-testing that a good source does not dislodge other good ones"+
" when swarming at capacity");
int capacity=ConnectionSettings.CONNECTION_SPEED.getValue();
ConnectionSettings.CONNECTION_SPEED.setValue(
SpeedConstants.MODEM_SPEED_INT);
final int RATE = 30;
testUploaders[0].setRate(RATE);
testUploaders[2].setRate(RATE);
testUploaders[1].setRate(RATE);
RemoteFileDesc rfd1=newRFDWithURN(PORTS[0], false);
RemoteFileDesc rfd2=newRFDWithURN(PORTS[1], false);
RemoteFileDesc[] rfds = {rfd1, rfd2};
RemoteFileDesc rfd3 = newRFDWithURN(PORTS[2], false);
ManagedDownloaderImpl downloader = null;
downloader=(ManagedDownloaderImpl)downloadServices.download(rfds, false, null);
Thread.sleep(2 * DownloadSettings.WORKER_INTERVAL.getValue()+ 1000);
int swarm = downloader.getActiveWorkers().size();
int queued = downloader.getQueuedHostCount();
assertEquals("incorrect swarming",2,swarm);
assertEquals("uploader 2 not queued ",0, queued);
//try to add a third
downloader.addDownloadForced(rfd3, true);
Thread.sleep(DownloadSettings.WORKER_INTERVAL.getValue()+ 1000);
//make sure we did not kill anybody
swarm = downloader.getActiveWorkers().size();
queued = downloader.getQueuedHostCount();
assertEquals("incorrect swarming",2,swarm);
assertEquals("uploader 2 not replaced ",0, queued);
waitForComplete();
if(isComplete())
LOG.debug("pass \n");
else
fail("FAILED: complete corrupt");
int u1 = testUploaders[0].getAmountUploaded();
int u2 = testUploaders[1].getAmountUploaded();
int u3 = testUploaders[2].getAmountUploaded();
// we only care that the 3rd downloader doesn't download anything -
// how the other two downloaders split the file between themselves
// doesn't matter.
assertGreaterThan("u1 did not do any work",0,u1);
assertGreaterThan("u2 did not do any work",0,u2);
assertGreaterThanOrEquals("u3 did some work",TestFile.length(),u1+u2);
assertEquals("u3 replaced a good downloader",0,u3);
ConnectionSettings.CONNECTION_SPEED.setValue(capacity);
}
public void testPartialDownloads() throws Exception {
LOG.info("-Testing partial downloads...");
testUploaders[0].setPartial(true);
RemoteFileDesc rfd1 = newRFDWithURN(PORTS[0], false);
RemoteFileDesc[] rfds = {rfd1};
Downloader downloader = downloadServices.download(rfds,false,null);
waitForBusy(downloader);
assertEquals("Downloader did not go to busy after getting ranges",
DownloadState.BUSY, downloader.getState());
}
/** Tests what happens if the content authority says no.
* LEAVE AS LAST -- (it does weird things otherwise) */
public void testContentInvalid() throws Exception {
LOG.info("-Testing partial downloads...");
RemoteFileDesc rfd1 = newRFDWithURN(PORTS[0], false);
RemoteFileDesc[] rfds = {rfd1};
testUploaders[0].setRate(50);
ContentSettings.CONTENT_MANAGEMENT_ACTIVE.setValue(true);
ContentSettings.USER_WANTS_MANAGEMENTS.setValue(true);
downloadServices.download(rfds,false,null);
Thread.sleep(1000);
synchronized(COMPLETE_LOCK) {
contentManager.handleContentResponse(new ContentResponse(TestFile.hash(), false));
waitForInvalid();
}
}
}