package com.limegroup.gnutella.downloader;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import junit.framework.Test;
import org.limewire.core.settings.ConnectionSettings;
import org.limewire.core.settings.DownloadSettings;
import org.limewire.core.settings.FilterSettings;
import org.limewire.core.settings.SpeedConstants;
import org.limewire.io.GUID;
import org.limewire.io.IpPort;
import org.limewire.io.IpPortImpl;
import org.limewire.io.IpPortSet;
import org.limewire.rudp.RUDPUtils;
import com.limegroup.gnutella.PushEndpoint;
import com.limegroup.gnutella.PushEndpointCache;
import com.limegroup.gnutella.RemoteFileDesc;
import com.limegroup.gnutella.altlocs.AlternateLocation;
import com.limegroup.gnutella.altlocs.AlternateLocationCollection;
import com.limegroup.gnutella.altlocs.PushAltLoc;
import com.limegroup.gnutella.stubs.NetworkManagerStub;
public class DownloadPushTest extends DownloadTestCase {
/* ports for the various push proxies */
private final int PPORT_1 = 10001;
private final int PPORT_2 = 10002;
private final int PPORT_3 = 10003;
private TestUDPAcceptorFactoryImpl testUDPAcceptorFactoryImpl;
public DownloadPushTest(String name) {
super(name);
}
public static Test suite() {
return buildTestSuite(DownloadPushTest.class);
}
@Override
protected void setUp() throws Exception {
FilterSettings.WHITE_LISTED_IP_ADDRESSES.setValue(new String[]{"127.*.*.*",
"1.1.1.1","1.2.3.4","6.7.8.9"});
super.setUp();
testUDPAcceptorFactoryImpl = injector.getInstance(TestUDPAcceptorFactoryImpl.class);
}
public void testSimplePushDownload() throws Exception {
int successfulPushes = ((AtomicInteger)((Map)statsTracker.inspect()).get("push connect success")).intValue();
LOG.info("-Testing non-swarmed push download");
GUID guid = new GUID();
AlternateLocation pushLoc = alternateLocationFactory.create(guid.toHexString()
+ ";127.0.0.1:" + PPORT_1, TestFile.hash());
((PushAltLoc) pushLoc).updateProxies(true);
RemoteFileDesc rfd = newRFDPush(guid, PPORT_1, 1);
assertTrue(rfd.getAddress() instanceof PushEndpoint);
RemoteFileDesc[] rfds = { rfd };
TestUploader uploader = injector.getInstance(TestUploader.class);
uploader.start("push uploader");
testUDPAcceptorFactoryImpl.createTestUDPAcceptor(PPORT_1, networkManager.getPort(), savedFile.getName(), uploader, guid, _currentTestName);
tGeneric(rfds);
assertEquals(successfulPushes + 1, ((AtomicInteger)((Map)statsTracker.inspect()).get("push connect success")).intValue());
}
public void testSimpleSwarmPush() throws Exception {
LOG.info("-Testing swarming from two sources, one push...");
GUID guid = new GUID();
RemoteFileDesc rfd1 = newRFDWithURN(PORTS[0], false);
AlternateLocation pushLoc = alternateLocationFactory.create(guid.toHexString()
+ ";127.0.0.1:" + PPORT_2, TestFile.hash());
((PushAltLoc) pushLoc).updateProxies(true);
RemoteFileDesc rfd2 = pushLoc.createRemoteFileDesc(TestFile.length(), remoteFileDescFactory);
TestUploader uploader = injector.getInstance(TestUploader.class);
uploader.start("push uploader");
uploader.setRate(100);
testUploaders[0].setRate(100);
RemoteFileDesc[] rfds = { rfd1, rfd2 };
testUDPAcceptorFactoryImpl.createTestUDPAcceptor(PPORT_2, networkManager.getPort(), savedFile.getName(), uploader, guid, _currentTestName);
tGeneric(rfds);
assertLessThan("u1 did all the work", TestFile.length(), testUploaders[0]
.fullRequestsUploaded());
assertGreaterThan("pusher did all the work ", 0, testUploaders[0].fullRequestsUploaded());
}
/**
* tests a generic swarm from a lot of sources with thex. Meant to be run repetitevely
* to find weird scheduling issues
*/
public void testBigSwarm() throws Exception {
LOG.info(" Testing swarming from many sources");
int capacity = ConnectionSettings.CONNECTION_SPEED.getValue();
ConnectionSettings.CONNECTION_SPEED.setValue(SpeedConstants.T3_SPEED_INT);
final int RATE = 10; // slow to allow swarming
RemoteFileDesc rfd1 = newRFDWithURN(PORTS[0], false);
RemoteFileDesc rfd2 = newRFDWithURN(PORTS[1], false);
RemoteFileDesc rfd3 = newRFDWithURN(PORTS[2], false);
RemoteFileDesc rfd4 = newRFDWithURN(PORTS[3], false);
RemoteFileDesc rfd5 = newRFDWithURN(PORTS[4], false);
GUID guid1 = new GUID();
GUID guid2 = new GUID();
GUID guid3 = new GUID();
RemoteFileDesc pushRFD1 = newRFDPush(guid1, PPORT_1, 1);
RemoteFileDesc pushRFD2 = newRFDPush(guid2, PPORT_2, 2);
RemoteFileDesc pushRFD3 = newRFDPush(guid3, PPORT_3, 3);
TestUploader first = injector.getInstance(TestUploader.class);
first.start("first pusher");
TestUploader second = injector.getInstance(TestUploader.class);
second.start("second pusher");
TestUploader third = injector.getInstance(TestUploader.class);
third.start("third pusher");
testUDPAcceptorFactoryImpl.createTestUDPAcceptor(PPORT_1, networkManager.getPort(), savedFile.getName(), first, guid1, _currentTestName);
testUDPAcceptorFactoryImpl.createTestUDPAcceptor(PPORT_2, networkManager.getPort(), savedFile.getName(), second, guid2, _currentTestName);
testUDPAcceptorFactoryImpl.createTestUDPAcceptor(PPORT_3, networkManager.getPort(), savedFile.getName(), third, guid3, _currentTestName);
testUploaders[0].setRate(RATE);
testUploaders[1].setRate(RATE);
testUploaders[2].setRate(RATE);
testUploaders[3].setRate(RATE);
testUploaders[4].setRate(RATE);
first.setRate(RATE);
second.setRate(RATE);
third.setRate(RATE);
testUploaders[0].setSendThexTreeHeader(true);
testUploaders[0].setSendThexTree(true);
RemoteFileDesc[] rfds = new RemoteFileDesc[] { rfd1, rfd2, rfd3, rfd4, rfd5, pushRFD1,
pushRFD2, pushRFD3, };
tGeneric(rfds);
// no assesrtions really - just test completion and observe behavior in logs
ConnectionSettings.CONNECTION_SPEED.setValue(capacity);
}
/**
* tests that an uploader will pass a push loc which will be included in the swarm
*/
public void testUploaderPassesPushLoc() throws Exception {
LOG.info("-Testing swarming from two sources one based on a push alt...");
final int RATE = 500;
testUploaders[0].setRate(RATE);
testUploaders[0].stopAfter(800000);
TestUploader pusher = injector.getInstance(TestUploader.class);
pusher.start("push uploader");
pusher.setRate(RATE);
GUID guid = new GUID();
AlternateLocation pushLoc = alternateLocationFactory.create(guid.toHexString()
+ ";127.0.0.1:" + PPORT_1, TestFile.hash());
AlternateLocationCollection<AlternateLocation> alCol = AlternateLocationCollection
.create(TestFile.hash());
alCol.add(pushLoc);
testUploaders[0].setGoodAlternateLocations(alCol);
RemoteFileDesc rfd = newRFDWithURN(PORTS[0], TestFile.hash().toString(), false);
RemoteFileDesc[] rfds = { rfd };
testUDPAcceptorFactoryImpl.createTestUDPAcceptor(PPORT_1, networkManager.getPort(), savedFile.getName(), pusher, guid, _currentTestName);
tGeneric(rfds);
assertGreaterThan("u1 didn't do enough work ", 100 * 1024, testUploaders[0]
.fullRequestsUploaded());
assertGreaterThan("pusher didn't do enough work ", 100 * 1024, pusher
.fullRequestsUploaded());
}
/**
* tests that a push uploader passes push loc and the new push loc receives
* the first uploader as an altloc.
*/
public void testPushUploaderPassesPushLoc() throws Exception {
LOG.info("Test push uploader passes push loc");
final int RATE = 500;
TestUploader first = injector.getInstance(TestUploader.class);
first.start("first pusher");
first.setRate(RATE / 3);
first.stopAfter(700000);
TestUploader second = injector.getInstance(TestUploader.class);
second.start("second pusher");
second.setRate(RATE);
second.stopAfter(700000);
second.setInterestedInFalts(true);
GUID guid = new GUID();
GUID guid2 = new GUID(GUID.makeGuid());
AlternateLocation firstLoc = alternateLocationFactory.create(guid.toHexString()
+ ";127.0.0.2:" + PPORT_1, TestFile.hash());
AlternateLocation pushLoc = alternateLocationFactory.create(guid2.toHexString()
+ ";127.0.0.2:" + PPORT_2, TestFile.hash());
AlternateLocationCollection<AlternateLocation> alCol = AlternateLocationCollection
.create(TestFile.hash());
alCol.add(pushLoc);
first.setGoodAlternateLocations(alCol);
testUDPAcceptorFactoryImpl.createTestUDPAcceptor(PPORT_1, networkManager.getPort(), savedFile.getName(), first, guid, _currentTestName);
testUDPAcceptorFactoryImpl.createTestUDPAcceptor(PPORT_2, networkManager.getPort(), savedFile.getName(), second, guid2, _currentTestName);
RemoteFileDesc[] rfd = { newRFDPush(guid, PPORT_1, 1, 2) };
tGeneric(rfd);
assertGreaterThan("first pusher did no work", 100000, first.fullRequestsUploaded());
assertGreaterThan("second pusher did no work", 100000, second.fullRequestsUploaded());
assertEquals(1, second.getIncomingGoodAltLocs().size());
assertTrue("interested uploader didn't get first loc", second.getIncomingGoodAltLocs()
.contains(firstLoc));
}
/**
* tests that a download from a push location becomes an alternate location.
*
* It creates a push uploader from which we must create a PushLoc.
* After a while, two open uploaders join the swarm -one which is interested
* in receiving push locs and one which isn't. The interested one should
* receive the push loc, the other one should not.
*/
public void testPusherBecomesPushLocAndSentToInterested() throws Exception {
LOG.info("-Testing push download creating a push location...");
final int RATE = 200;
testUploaders[0].setRate(RATE);
testUploaders[0].setInterestedInFalts(true);
testUploaders[0].stopAfter(600000);
testUploaders[1].setRate(RATE);
testUploaders[1].setInterestedInFalts(false);
testUploaders[1].stopAfter(300000);
TestUploader pusher = injector.getInstance(TestUploader.class);
pusher.start("push uploader");
pusher.setRate(RATE);
pusher.stopAfter(200000);
GUID guid = new GUID();
AlternateLocation pushLoc = alternateLocationFactory.create(guid.toHexString()
+ ";127.0.0.2:" + PPORT_1, TestFile.hash());
RemoteFileDesc pushRFD = newRFDPush(guid, PPORT_1, 1, 2);
PushEndpoint pushEndpoint = (PushEndpoint) pushRFD.getAddress();
assertEquals(0, pushEndpoint.getFWTVersion());
RemoteFileDesc openRFD1 = newRFDWithURN(PORTS[0], TestFile.hash().toString(), false);
RemoteFileDesc openRFD2 = newRFDWithURN(PORTS[1], TestFile.hash().toString(), false);
RemoteFileDesc[] now = { pushRFD };
HashSet<RemoteFileDesc> later = new HashSet<RemoteFileDesc>();
later.add(openRFD1);
later.add(openRFD2);
testUDPAcceptorFactoryImpl.createTestUDPAcceptor(PPORT_1, networkManager.getPort(), savedFile.getName(), pusher, guid, _currentTestName);
ManagedDownloader download = (ManagedDownloader) downloadServices.download(now,
RemoteFileDesc.EMPTY_LIST, null, false);
Thread.sleep(1000);
download.addDownload(later, false);
waitForComplete();
assertGreaterThan("u1 did no work", 100000, testUploaders[0].getAmountUploaded());
assertGreaterThan("u2 did no work", 100000, testUploaders[1].getAmountUploaded());
assertLessThan("u2 did too much work", 550 * 1024, testUploaders[1].getAmountUploaded());
assertGreaterThan("pusher did no work", 100 * 1024, pusher.getAmountUploaded());
List alc = testUploaders[0].getIncomingGoodAltLocs();
assertTrue("interested uploader did not get pushloc", alc.contains(pushLoc));
alc = testUploaders[1].getIncomingGoodAltLocs();
assertFalse("not interested uploader got pushloc", alc.contains(pushLoc));
alc = pusher.getIncomingGoodAltLocs();
assertFalse("not interested uploader got pushloc", alc.contains(pushLoc));
}
/**
* tests that a pushloc which we thought did not support FWT
* but actually does updates its status through the headers,
* as well as that the set of push proxies is getting updated.
*
* This test that the X-FWTP is parsed and the push endpoint address and port
* are updated with the value
*/
// problem is:
// old code ranked as follows: GUID:C72D25808E87DE738FD57BCF51F5FF00, address: 1.1.1.1:6346,
// proxies:{ /127.0.0.2:10002
// }]
//
// GUID:C72D25808E87DE738FD57BCF51F5FF00, address: 127.0.0.1:7498,
// proxies:{ /1.2.3.4:5
// /6.7.8.9:10
//
// new code picks:
// GUID:7ECD430C3F5E93BB76B5CF3706C40700, address: 127.0.0.1:6346,
// proxies:{ /127.0.0.2:10002
//
// GUID:7ECD430C3F5E93BB76B5CF3706C40700, address: 127.0.0.1:7498,
// proxies:{ /1.2.3.4:5
// /6.7.8.9:10
//
// GUID:7ECD430C3F5E93BB76B5CF3706C40700, address: 127.0.0.1:7498,
// proxies:{ /1.2.3.4:5
// /6.7.8.9:10
// /127.0.0.2:10002
// }]
public void testPushLocUpdatesStatus() throws Exception {
int successfulPushes = ((AtomicInteger)((Map)statsTracker.inspect()).get("push connect success")).intValue();
LOG.info("testing that a push loc updates its status");
final int RATE = 100;
final int FWTPort = 7498;
NetworkManagerStub uploaderNetworkManager = new NetworkManagerStub();
uploaderNetworkManager.setAcceptedIncomingConnection(false);
uploaderNetworkManager.setCanDoFWT(true);
udpService.setReceiveSolicited(true);
testUploaders[0].setRate(RATE);
testUploaders[0].stopAfter(900000);
testUploaders[0].setInterestedInFalts(true);
TestUploader pusher2 = new TestUploader(uploaderNetworkManager);
pusher2.start("firewalled pusher");
pusher2.setRate(RATE);
pusher2.stopAfter(200000);
pusher2.setFirewalled(true);
pusher2.setProxiesString("1.2.3.4:5,6.7.8.9:10");
pusher2.setInterestedInFalts(true);
pusher2.setFWTPort(FWTPort);
GUID guid = new GUID();
// register proxies for GUID, this will add 127.0.0.2:10002 to proxies
PushEndpoint cachedPE = pushEndpointFactory.createPushEndpoint(guid.bytes(), new IpPortSet(new IpPortImpl("127.0.0.2", PPORT_2)));
PushEndpointCache cache = injector.getInstance(PushEndpointCache.class);
GUID retGuid = cache.updateProxiesFor(guid, cachedPE, true);
assertSame(retGuid, guid);
assertEquals(1, cachedPE.getProxies().size());
RemoteFileDesc openRFD = newRFDWithURN(PORTS[0], false);
RemoteFileDesc pushRFD2 = newRFDPush(guid, PPORT_2, 1, 2);
PushEndpoint pushEndpoint = (PushEndpoint) pushRFD2.getAddress();
assertEquals(0, pushEndpoint.getFWTVersion());
testUDPAcceptorFactoryImpl.createTestUDPAcceptor(PPORT_2, networkManager.getPort(), savedFile.getName(), pusher2, guid, _currentTestName);
// start download with rfd that needs udp push request
ManagedDownloader download = (ManagedDownloader) downloadServices.download(
new RemoteFileDesc[] { pushRFD2 }, RemoteFileDesc.EMPTY_LIST, null, false);
Thread.sleep(2000);
LOG.debug("adding regular downloader");
// also download from uploader1, so it gets the proxy headers from pusher2
download.addDownload(openRFD, false);
waitForComplete();
List<AlternateLocation> alc = testUploaders[0].getIncomingGoodAltLocs();
assertEquals(1, alc.size());
PushAltLoc pushLoc = (PushAltLoc) alc.iterator().next();
assertEquals(RUDPUtils.VERSION, pushLoc.supportsFWTVersion());
RemoteFileDesc readRFD = pushLoc.createRemoteFileDesc(1, remoteFileDescFactory);
pushEndpoint = (PushEndpoint) readRFD.getAddress();
assertTrue(pushEndpoint.getFWTVersion() > 0);
assertEquals(pushEndpoint.getPort(), FWTPort);
Set<IpPort> expectedProxies = new IpPortSet(new IpPortImpl("1.2.3.4:5"), new IpPortImpl("6.7.8.9:10"));
assertEquals("expected: " + expectedProxies + ", actual: " + pushEndpoint.getProxies(),
expectedProxies.size(), pushEndpoint.getProxies().size());
assertTrue(expectedProxies.containsAll(pushEndpoint.getProxies()));
assertEquals(successfulPushes + 1, ((AtomicInteger)((Map)statsTracker.inspect()).get("push connect success")).intValue());
}
/**
* tests that when we receive a headpong claiming that it doesn't have the file,
* we send out an NAlt for that source
*/
public void testHeadPongNAlts() throws Exception {
testUploaders[0].setRate(100);
testUploaders[1].setRate(100);
int sleep = DownloadSettings.WORKER_INTERVAL.getValue();
// make sure we use the ping ranker
networkManager.setCanReceiveSolicited(true);
assertTrue(networkManager.canReceiveSolicited());
assertTrue(sourceRankerFactory.getAppropriateRanker() instanceof FriendsFirstSourceRanker);
// create one source that will actually download and another one to which a headping should be sent
RemoteFileDesc rfd = newRFDWithURN(PORTS[0], false);
RemoteFileDesc noFile = newRFDWithURN(PORTS[1], false);
AlternateLocation toBeDemoted = alternateLocationFactory.create(noFile);
// create a listener for the headping
TestUDPAcceptor l = testUDPAcceptorFactoryImpl.createTestUDPAcceptor(PORTS[1], _currentTestName);
ManagedDownloaderImpl download = (ManagedDownloaderImpl) downloadServices.download(
new RemoteFileDesc[] { rfd }, RemoteFileDesc.EMPTY_LIST, null, false);
SourceRanker ranker = download.getCurrentSourceRanker();
assertTrue(ranker instanceof FriendsFirstSourceRanker);
LOG.debug("started download");
// after a while clear the ranker and add the second host.
Thread.sleep((int) (sleep * 1.5));
ranker.stop();
ranker.setMeshHandler(download);
download.addDownload(noFile, false);
LOG.debug("waiting for download to complete");
waitForComplete();
// the first downloader should have received an NAlt
assertTrue(testUploaders[0].getIncomingBadAltLocs().contains(toBeDemoted));
// the first uploader should have uploaded the whole file
assertGreaterThan(0, testUploaders[0].getConnections());
assertEquals(TestFile.length(), testUploaders[0].fullRequestsUploaded());
// the second downloader should not be contacted
assertEquals(0, testUploaders[1].getConnections());
assertEquals(0, testUploaders[1].getAmountUploaded());
// only one ping should have been sent to the second uploader
assertEquals(1, l.pings);
l.shutdown();
}
/**
* tests that bad push locs get removed
*/
public void testBadPushLocGetsDemotedNotAdvertised() throws Exception {
setDownloadWaitTime(2 * DOWNLOAD_WAIT_TIME);
LOG.info("test that bad push loc gets demoted and not advertised");
// this test needs to go slowly so that the push attempt may time out
final int RATE=15;
testUploaders[0].setInterestedInFalts(true);
testUploaders[1].setInterestedInFalts(true);
testUploaders[0].setRate(RATE);
testUploaders[1].setRate(RATE);
testUploaders[0].stopAfter(550000);
testUploaders[1].stopAfter(550000);
GUID guid = new GUID();
AlternateLocation badPushLoc=alternateLocationFactory.create(
guid.toHexString()+";1.2.3.4:5",TestFile.hash());
((PushAltLoc)badPushLoc).updateProxies(true);
AlternateLocationCollection<AlternateLocation> alc =
AlternateLocationCollection.create(TestFile.hash());
alc.add(badPushLoc);
testUploaders[0].setGoodAlternateLocations(alc);
RemoteFileDesc rfd1 = newRFDWithURN(PORTS[0], false);
RemoteFileDesc rfd2 = newRFDWithURN(PORTS[1], false);
RemoteFileDesc [] rfds = {rfd1,rfd2};
tGeneric(rfds);
assertGreaterThan("u1 did no work",100*1024,testUploaders[0].fullRequestsUploaded());
assertGreaterThan("u2 did no work",100*1024,testUploaders[1].fullRequestsUploaded());
assertFalse("bad pushloc got advertised",
testUploaders[1].getIncomingGoodAltLocs().contains(badPushLoc));
assertEquals(1,testUploaders[0].getIncomingGoodAltLocs().size());
assertTrue(testUploaders[0].getIncomingGoodAltLocs().contains(alternateLocationFactory.create(rfd2)));
assertEquals(1,testUploaders[0].getIncomingBadAltLocs().size());
AlternateLocation current = testUploaders[0].getIncomingBadAltLocs().get(0);
assertTrue(current instanceof PushAltLoc);
PushAltLoc pcurrent = (PushAltLoc)current;
assertEquals(guid.bytes(), pcurrent.getPushAddress().getClientGUID());
// Now get the PE from our cache and make sure no proxies exist & its demoted.
PushEndpoint pe = injector.getInstance(PushEndpointCache.class).getPushEndpoint(guid);
assertTrue("pe: " + pe, pe.getProxies().isEmpty());
assertTrue("pe: " + pe, badPushLoc.isDemoted());
}
}