package com.limegroup.gnutella.messages.vendor;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.net.InetAddress;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import junit.framework.Test;
import com.limegroup.gnutella.Acceptor;
import com.limegroup.gnutella.GUID;
import com.limegroup.gnutella.HugeTestUtils;
import com.limegroup.gnutella.ManagedConnectionStub;
import com.limegroup.gnutella.PushEndpoint;
import com.limegroup.gnutella.RemoteFileDesc;
import com.limegroup.gnutella.RouterService;
import com.limegroup.gnutella.URN;
import com.limegroup.gnutella.altlocs.AlternateLocation;
import com.limegroup.gnutella.altlocs.AlternateLocationCollection;
import com.limegroup.gnutella.altlocs.PushAltLoc;
import com.limegroup.gnutella.downloader.Interval;
import com.limegroup.gnutella.settings.SharingSettings;
import com.limegroup.gnutella.settings.UploadSettings;
import com.limegroup.gnutella.stubs.ConnectionManagerStub;
import com.limegroup.gnutella.stubs.FileDescStub;
import com.limegroup.gnutella.stubs.FileManagerStub;
import com.limegroup.gnutella.stubs.IncompleteFileDescStub;
import com.limegroup.gnutella.stubs.MessageRouterStub;
import com.limegroup.gnutella.stubs.UploadManagerStub;
import com.limegroup.gnutella.util.BaseTestCase;
import com.limegroup.gnutella.util.IntervalSet;
import com.limegroup.gnutella.util.PrivilegedAccessor;
/**
* this class tests the handling of udp head requests and responses.
*/
public class HeadTest extends BaseTestCase {
/**
* keep a file manager which shares one complete file and one incomplete file
*/
static FileManagerStub _fm;
static UploadManagerStub _um;
/**
* two collections of altlocs, one for the complete and one for the incomplete file
*/
static AlternateLocationCollection _alCollectionComplete,_alCollectionIncomplete,
_pushCollection;
/**
* URNs for the 3 files that will be requested
*/
static URN _haveFull,_notHave,_havePartial;
/**
* file descs for the partial and complete files
*/
static IncompleteFileDescStub _partial;
static FileDescStub _complete;
/**
* an interval that can fit in a packet, and one that can't
*/
static IntervalSet _ranges, _rangesMedium, _rangesJustFit, _rangesTooBig;
static PushEndpoint pe;
static int PACKET_SIZE;
public HeadTest(String name) {
super(name);
}
public static Test suite() {
return buildTestSuite(HeadTest.class);
}
private static final byte [] SOMEGUID=GUID.makeGuid();
/**
* sets up the testing environment for the UDPHeadPong.
* two files are shared - _complete and _incomplete
* _complete has altlocs _altlocCollectionComplete
* _incomplete has altlocs _altlocCollectionIncomplete
* _incomplete has available ranges _ranges
*
* @throws Exception
*/
public static void globalSetUp() throws Exception{
SharingSettings.ADD_ALTERNATE_FOR_SELF.setValue(false);
MessageRouterStub mrStub = new MessageRouterStub() {
public byte[] getOurGUID() {
return SOMEGUID;
}
};
PrivilegedAccessor.setValue(RouterService.class,"router",mrStub);
final InetAddress addr = InetAddress.getByName("1.2.3.4");
ManagedConnectionStub mStub = new ManagedConnectionStub();
final Set conns = new HashSet();
conns.add(mStub);
ConnectionManagerStub cmStub = new ConnectionManagerStub() {
public Set getPushProxies() {
return conns;
}
};
PrivilegedAccessor.setValue(RouterService.class,"manager",cmStub);
//PrivilegedAccessor.setValue(RouterService.class,"acceptor", new AcceptorStub());
_fm = new FileManagerStub();
_um = new UploadManagerStub();
int base=0;
_ranges = new IntervalSet();
for (int i=2;i<10;i++) {
int low = base;
_ranges.add(new Interval(low,low+i));
base+=2*i;
}
base=0;
_rangesMedium = new IntervalSet();
for (int i=2;i<70;i++) {
int low = base;
_rangesMedium.add(new Interval(low,low+i));
base+=2*i;
}
base=0;
_rangesJustFit = new IntervalSet();
for (int i=2;i<73;i++) {
int low = base;
_rangesJustFit.add(new Interval(low,low+i));
base+=2*i;
}
base=0;
_rangesTooBig = new IntervalSet();
for (int i=2;i<220;i++) {
int low = base;
_rangesTooBig.add(new Interval(low,low+i));
base+=2*i;
}
_haveFull = URN.createSHA1Urn("urn:sha1:PLSTHIPQGSSZTS5FJUPAKUZWUGYQYPFE");
_notHave = FileManagerStub._notHave;
_havePartial = URN.createSHA1Urn("urn:sha1:PLSTHIPQGSSZTS5FJUPAKUZWUGYQYPFD");
createCollections();
_partial = new IncompleteFileDescStub("incomplete",_havePartial,3);
_partial.setRangesByte(_ranges.toBytes());
_complete = new FileDescStub("complete",_haveFull,2);
Map urns = new HashMap();
urns.put(_havePartial,_partial);
urns.put(_haveFull,_complete);
List descs = new LinkedList();
descs.add(_partial);
descs.add(_complete);
_fm = new FileManagerStub(urns,descs);
assertEquals(_partial,_fm.getFileDescForUrn(_havePartial));
assertEquals(_complete,_fm.getFileDescForUrn(_haveFull));
PrivilegedAccessor.setValue(HeadPong.class, "_fileManager",_fm);
PrivilegedAccessor.setValue(HeadPong.class, "_uploadManager",_um);
PACKET_SIZE = ((Integer)PrivilegedAccessor.getValue(HeadPong.class,"PACKET_SIZE")).intValue();
}
/**
* tests the scenario where the file cannot be found.
*/
public void testFileNotFound() throws Exception {
HeadPing ping = new HeadPing(_notHave);
HeadPong pong = reparse(new HeadPong(ping));
assertEquals(pong.getGUID(),ping.getGUID());
assertFalse(pong.hasFile());
assertFalse(pong.hasCompleteFile());
assertNull(pong.getAltLocs());
assertNull(pong.getRanges());
}
/**
* tests the scenarios where an incomplete and complete files are
* behind firewall or open.
*/
public void testFirewalled() throws Exception {
Acceptor acceptor = RouterService.getAcceptor();
PrivilegedAccessor.setValue(acceptor,"_acceptedIncoming", new Boolean(false));
assertFalse(RouterService.acceptedIncomingConnection());
HeadPing ping = new HeadPing(_haveFull);
HeadPing pingi = new HeadPing(_havePartial);
HeadPong pong = reparse(new HeadPong(ping));
HeadPong pongi = reparse(new HeadPong(pingi));
assertEquals(ping.getGUID(),pong.getGUID());
assertEquals(pingi.getGUID(),pongi.getGUID());
assertTrue(pong.hasFile());
assertTrue(pong.isFirewalled());
assertTrue(pong.hasCompleteFile());
assertNull(pong.getAltLocs());
assertNull(pong.getRanges());
assertTrue(pongi.hasFile());
assertTrue(pongi.isFirewalled());
assertFalse(pongi.hasCompleteFile());
assertNull(pongi.getAltLocs());
assertNull(pongi.getRanges());
PrivilegedAccessor.setValue(acceptor,"_acceptedIncoming", new Boolean(true));
assertTrue(RouterService.acceptedIncomingConnection());
ping = new HeadPing(_haveFull);
pingi = new HeadPing(_havePartial);
pong = reparse(new HeadPong(ping));
pongi = reparse(new HeadPong(pingi));
assertEquals(pong.getGUID(),ping.getGUID());
assertEquals(pingi.getGUID(),pongi.getGUID());
assertFalse(pong.isFirewalled());
assertTrue(pong.hasFile());
assertTrue(pong.hasCompleteFile());
assertNull(pong.getAltLocs());
assertNull(pong.getRanges());
assertTrue(pongi.hasFile());
assertFalse(pongi.isFirewalled());
assertFalse(pongi.hasCompleteFile());
assertNull(pongi.getAltLocs());
assertNull(pongi.getRanges());
}
/**
* tests whether the downloading flag is set properly.
*/
public void testDownloading() throws Exception {
//replace the downloadManger with a stub
Object originalDM = RouterService.getDownloadManager();
_partial.setActivelyDownloading(true);
HeadPing ping = new HeadPing(_havePartial);
HeadPong pong = reparse (new HeadPong(ping));
assertTrue(pong.isDownloading());
_partial.setActivelyDownloading(false);
pong = reparse (new HeadPong(ping));
assertFalse(pong.isDownloading());
//restore the original download manager
PrivilegedAccessor.setValue(RouterService.class,"downloader",originalDM);
}
/**
* tests requesting ranges from complete, incomplete files
* as well as requesting too big ranges to fit in packet.
*/
public void testRanges() throws Exception {
HeadPing ping = new HeadPing(new GUID(GUID.makeGuid()),_haveFull,HeadPing.INTERVALS);
HeadPing pingi = new HeadPing(new GUID(GUID.makeGuid()),_havePartial,HeadPing.INTERVALS);
HeadPong pong = reparse(new HeadPong(ping));
HeadPong pongi = reparse(new HeadPong(pingi));
assertTrue(pong.hasCompleteFile());
assertFalse(pongi.hasCompleteFile());
assertNull(pong.getRanges());
assertNotNull(pongi.getRanges());
assertTrue(Arrays.equals(_ranges.toBytes(),pongi.getRanges().toBytes()));
//now make the incomplete file desc carry ranges which are too big to
//fit in a packet
_partial.setRangesByte(_rangesTooBig.toBytes());
pingi = new HeadPing(new GUID(GUID.makeGuid()),_havePartial,HeadPing.INTERVALS);
pongi = reparse(new HeadPong(pingi));
assertNull(pongi.getRanges());
assertLessThan(PACKET_SIZE,pongi.getPayload().length);
_partial.setRangesByte(_ranges.toBytes());
}
/**
* tests various values for the queue rank
*/
public void testQueueStatus() throws Exception {
HeadPing ping = new HeadPing(_havePartial);
HeadPong pong = reparse(new HeadPong(ping));
int allFree = pong.getQueueStatus();
assertLessThan(0,allFree);
_um.setUploadsInProgress(10);
pong = reparse(new HeadPong(ping));
assertEquals(allFree+10,pong.getQueueStatus());
_um.setNumQueuedUploads(5);
pong = reparse(new HeadPong(ping));
assertEquals(5,pong.getQueueStatus());
_um.setUploadsInProgress(UploadSettings.HARD_MAX_UPLOADS.getValue());
_um.setNumQueuedUploads(0);
pong = reparse(new HeadPong(ping));
assertEquals(0,pong.getQueueStatus());
_um.setIsBusy(true);
_um.setNumQueuedUploads(UploadSettings.UPLOAD_QUEUE_SIZE.getValue());
pong = reparse(new HeadPong(ping));
assertGreaterThanOrEquals(0x7F,pong.getQueueStatus());
}
/**
* tests handling of alternate locations.
*/
public void testAltLocs() throws Exception {
//add some big interval that fill most of the packet but not all
_partial.setRangesByte(_rangesMedium.toBytes());
//ping 1 should contain alternate locations.
//the second ping should be too big to contain all altlocs.
HeadPing ping1 = new HeadPing(new GUID(GUID.makeGuid()),_haveFull,HeadPing.ALT_LOCS);
HeadPing ping2 = new HeadPing(new GUID(GUID.makeGuid()),_havePartial,
HeadPing.ALT_LOCS | HeadPing.INTERVALS);
HeadPong pong1 = reparse (new HeadPong(ping1));
HeadPong pong2 = reparse (new HeadPong(ping2));
assertNull(pong1.getRanges());
assertNotNull(pong2.getRanges());
assertTrue(Arrays.equals(_rangesMedium.toBytes(),pong2.getRanges().toBytes()));
assertGreaterThan(pong1.getPayload().length,pong2.getPayload().length);
assertLessThan(pong1.getAltLocs().size(),pong2.getAltLocs().size());
assertLessThan(PACKET_SIZE,pong2.getPayload().length);
//now test if no locs will fit because of too many ranges
_partial.setRangesByte(_rangesJustFit.toBytes());
ping2 = new HeadPing(new GUID(GUID.makeGuid()),_havePartial,
HeadPing.ALT_LOCS | HeadPing.INTERVALS);
pong2 = reparse (new HeadPong(ping2));
assertNotNull(pong2.getRanges());
assertNull(pong2.getAltLocs());
//restore medium ranges to partial file
_partial.setRangesByte(_rangesMedium.toBytes());
}
public void testFirewalledAltlocs() throws Exception {
//try with a file that doesn't have push locs
HeadPing ping1 = new HeadPing(new GUID(GUID.makeGuid()),_haveFull,HeadPing.PUSH_ALTLOCS);
assertTrue(ping1.requestsPushLocs());
HeadPong pong1 = reparse (new HeadPong(ping1));
assertNull(pong1.getPushLocs());
ping1 = new HeadPing(new GUID(GUID.makeGuid()),_havePartial,HeadPing.PUSH_ALTLOCS);
assertTrue(ping1.requestsPushLocs());
pong1 = reparse (new HeadPong(ping1));
assertNull(pong1.getRanges());
assertNull(pong1.getAltLocs());
assertNotNull(pong1.getPushLocs());
RemoteFileDesc dummy =
new RemoteFileDesc("www.limewire.org", 6346, 10, "asdf",
10, GUID.makeGuid(), 10, true, 2, true, null,
HugeTestUtils.URN_SETS[1],
false,false,"",0,null, -1);
Set received = pong1.getAllLocsRFD(dummy);
assertEquals(1,received.size());
RemoteFileDesc rfd = (RemoteFileDesc)received.toArray()[0];
PushEndpoint point = rfd.getPushAddr();
assertEquals(pe,point);
assertEquals(pe.getProxies().size(),point.getProxies().size());
HashSet parsedProxies = new HashSet(point.getProxies());
parsedProxies.retainAll(pe.getProxies());
assertEquals(pe.getProxies().size(),parsedProxies.size());
//now ask only for fwt push locs - nothing returned
ping1 = new HeadPing(new GUID(GUID.makeGuid()),_havePartial,HeadPing.PUSH_ALTLOCS | HeadPing.FWT_PUSH_ALTLOCS);
assertTrue(ping1.requestsFWTPushLocs());
pong1 = reparse(new HeadPong(ping1));
assertNull(pong1.getPushLocs());
}
public void testMixedLocs() throws Exception {
HeadPing ping = new HeadPing(new GUID(GUID.makeGuid()),_havePartial,
HeadPing.PUSH_ALTLOCS | HeadPing.ALT_LOCS);
HeadPong pong = reparse(new HeadPong(ping));
assertNotNull(pong.getAltLocs());
assertNotNull(pong.getPushLocs());
RemoteFileDesc rfd = new RemoteFileDesc(
"1.2.3.4",1,1,"filename",
1,null,1,
false,1,false,
null,null,
false,false,
"",0,
null,1);
Set rfds = pong.getAllLocsRFD(rfd);
assertEquals(pong.getAltLocs().size() + pong.getPushLocs().size(),
rfds.size());
}
private HeadPong reparse(HeadPong original) throws Exception{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
original.write(baos);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
return (HeadPong) HeadPong.read(bais);
}
private static void createCollections() throws Exception{
_alCollectionComplete=AlternateLocationCollection.create(_haveFull);
_alCollectionIncomplete=AlternateLocationCollection.create(_havePartial);
_pushCollection=AlternateLocationCollection.create(_havePartial);
for(int i=0;i<10;i++ ) {
AlternateLocation al = AlternateLocation.create("1.2.3."+i+":1234",_haveFull);
RouterService.getAltlocManager().add(al, null);
}
_alCollectionComplete = RouterService.getAltlocManager().getDirect(_haveFull);
assertEquals("failed to set test up",10,
_alCollectionComplete.getAltLocsSize());
for(int i=0;i<10;i++ ) {
AlternateLocation al = AlternateLocation.create("1.2.3."+i+":1234",_havePartial);
RouterService.getAltlocManager().add(al, null);
}
_alCollectionIncomplete = RouterService.getAltlocManager().getDirect(_havePartial);
assertEquals("failed to set test up",10,
_alCollectionIncomplete.getAltLocsSize());
//add some firewalled altlocs to the incomplete collection
GUID guid = new GUID(GUID.makeGuid());
AlternateLocation firewalled = AlternateLocation.create(guid.toHexString()+
";1.2.3.4:5",_havePartial);
((PushAltLoc)firewalled).updateProxies(true);
pe = ((PushAltLoc)firewalled).getPushAddress();
RouterService.getAltlocManager().add(firewalled, null);
_pushCollection = RouterService.getAltlocManager().getPush(_havePartial, false);
}
}