package com.limegroup.gnutella.downloader;
import java.io.IOException;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ScheduledExecutorService;
import junit.framework.Test;
import org.limewire.collection.Cancellable;
import org.limewire.collection.IntervalSet;
import org.limewire.core.settings.DownloadSettings;
import org.limewire.gnutella.tests.LimeTestCase;
import org.limewire.gnutella.tests.LimeTestUtils;
import org.limewire.gnutella.tests.NetworkManagerStub;
import org.limewire.io.Connectable;
import org.limewire.io.ConnectableImpl;
import org.limewire.io.GUID;
import org.limewire.io.IpPort;
import org.limewire.io.IpPortImpl;
import org.limewire.io.IpPortSet;
import com.google.inject.AbstractModule;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import com.limegroup.gnutella.MessageListener;
import com.limegroup.gnutella.MessageRouter;
import com.limegroup.gnutella.NetworkManager;
import com.limegroup.gnutella.PushEndpoint;
import com.limegroup.gnutella.PushEndpointFactory;
import com.limegroup.gnutella.RemoteFileDesc;
import com.limegroup.gnutella.UDPPinger;
import com.limegroup.gnutella.UDPPingerImpl;
import com.limegroup.gnutella.UDPReplyHandlerFactory;
import com.limegroup.gnutella.UDPService;
import com.limegroup.gnutella.URN;
import com.limegroup.gnutella.messages.Message;
import com.limegroup.gnutella.messages.PingRequestFactory;
import com.limegroup.gnutella.messages.vendor.HeadPing;
import com.limegroup.gnutella.messages.vendor.HeadPong;
import com.limegroup.gnutella.messages.vendor.HeadPongFactory;
import com.limegroup.gnutella.messages.vendor.HeadPongImpl;
import com.limegroup.gnutella.stubs.MessageRouterStub;
/**
* tests the functioning of the ping ranker, i.e. how it sends out headpings
* and how it ranks hosts based on the returned results.
*
*/
public class PingRankerTest extends LimeTestCase {
private static final Set<PushEndpoint> EMPTY_PUSH_ENDPOINT_SET =
Collections.emptySet();
private MockPinger pinger;
private PingRanker ranker;
private NetworkManagerStub networkManager;
private UDPReplyHandlerFactory udpReplyHandlerFactory;
private PushEndpointFactory pushEndpointFactory;
private HeadPongFactory headPongFactory;
private RemoteFileDescFactory remoteFileDescFactory;
private ConcurrentMap<RemoteFileDesc, RemoteFileDescContext> contexts =
new ConcurrentHashMap<RemoteFileDesc, RemoteFileDescContext>();
public PingRankerTest(String name) {
super(name);
}
public static Test suite() {
return buildTestSuite(PingRankerTest.class);
}
@Override
public void setUp() throws Exception {
networkManager = new NetworkManagerStub();
networkManager.setAcceptedIncomingConnection(false);
Module module = new AbstractModule() {
@Override
protected void configure() {
bind(UDPPinger.class).to(MockPinger.class);
bind(NetworkManager.class).toInstance(networkManager);
bind(MessageRouter.class).to(MessageRouterStub.class);
}
};
Injector i = LimeTestUtils.createInjectorNonEagerly(module);
udpReplyHandlerFactory = i.getInstance(UDPReplyHandlerFactory.class);
pushEndpointFactory = i.getInstance(PushEndpointFactory.class);
headPongFactory = i.getInstance(HeadPongFactory.class);
pinger = (MockPinger)i.getInstance(UDPPinger.class);
remoteFileDescFactory = i.getInstance(RemoteFileDescFactory.class);
ranker = i.getInstance(PingRanker.class);
ranker.setMeshHandler(new MockMesh(ranker));
DownloadSettings.WORKER_INTERVAL.setValue(-1);
DownloadSettings.MAX_VERIFIED_HOSTS.revertToDefault();
DownloadSettings.PING_BATCH.revertToDefault();
}
/**
* Tests that the ranker sends out a HeadPing requesting ranges and alts to given hosts.
*/
public void testPingsNewHosts() throws Exception {
for (int i =1;i <= 10;i++)
ranker.addToPool(newRFDWithURN("1.2.3."+i,3));
assertEquals(10,pinger.hosts.size());
assertEquals(10,pinger.messages.size());
for (int i = 0 ;i < 10; i++) {
pinger.hosts.contains(newRFDWithURN("1.2.3."+i,3));
HeadPing ping = (HeadPing) pinger.messages.get(i);
assertTrue(ping.requestsRanges());
assertTrue(ping.requestsAltlocs());
}
}
/**
* Tests that the ranker stops looking for new hosts once it has found enough.
*/
public void testStopsPinging() throws Exception {
DownloadSettings.MAX_VERIFIED_HOSTS.setValue(1);
ranker.addToPool(newRFDWithURN("1.2.3.4",3));
assertEquals(1,pinger.hosts.size());
// get a reply from that host
MockPong pong = new MockPong(true,true,-1,false,false,true,null);
ranker.processMessage(pong, udpReplyHandlerFactory.createUDPReplyHandler(InetAddress.getByName("1.2.3.4"), 1));
// add some more hosts
for (int i =1;i <= 10;i++)
ranker.addToPool(newRFDWithURN("1.2.3."+i,3));
// no more pings should have been sent out.
assertEquals(1,pinger.hosts.size());
// consume the host we know about
ranker.getBest();
// we should send out some more pings
assertGreaterThan(1,pinger.hosts.size());
}
/**
* Tests that the ranker learns about new hosts from altlocs
*/
public void testLearnsFromAltLocs() throws Exception {
networkManager.setAcceptedIncomingConnection(true);
RemoteFileDescContext original = newRFDWithURN("1.2.3.4",3);
ranker.addToPool(original);
assertEquals(1,pinger.hosts.size());
pinger.hosts.clear();
// send two altlocs, one containing the node itself
IpPort ip = new IpPortImpl("1.2.3.5",1);
Set<IpPort> alts = new IpPortSet();
alts.add(ip);
//and one push loc
PushEndpoint pe = pushEndpointFactory.createPushEndpoint((new GUID(GUID.makeGuid())).toHexString()+";1.2.3.6:7");
Set<PushEndpoint> push = new HashSet<PushEndpoint>();
push.add(pe);
MockPong pong = new MockPong(true,true,1,false,false,false,null,alts,push);
MockMesh mesh = new MockMesh(ranker);
ranker.setMeshHandler(mesh);
ranker.processMessage(pong, udpReplyHandlerFactory.createUDPReplyHandler(InetAddress.getByName("1.2.3.4"), 1));
assertNotNull(mesh.sources);
ranker.addToPool(toContexts(mesh.sources));
// now the ranker should know about more than one host.
// the best host should be the one that actually replied.
RemoteFileDescContext best = ranker.getBest();
assertEquals(original,best);
// the ranker should have more available hosts, even if we haven't
// pinged any.
assertTrue(ranker.hasMore());
// the ranker should have pinged the other two hosts.
assertEquals(2,pinger.hosts.size());
}
/**
* Tests that the ranker does not add altlocs it already knows about
* either from other altlocs or from direct addition
*/
public void testIgnoresDuplicateAlts() throws Exception {
networkManager.setAcceptedIncomingConnection(true);
RemoteFileDescContext original = newRFDWithURN("1.2.3.4",3);
GUID g = new GUID(GUID.makeGuid());
RemoteFileDescContext original2 = newPushRFD(g.bytes(),"2.2.2.2:2;3.3.3.3:3","1.2.3.6:7");
ranker.addToPool(original);
ranker.addToPool(original2);
assertEquals(3,pinger.hosts.size());
pinger.hosts.clear();
// make one of the hosts send an altloc of itself (spammer?) and the pushloc
IpPort ip = new IpPortImpl("1.2.3.4",1);
PushEndpoint pe = pushEndpointFactory.createPushEndpoint(g.toHexString()+";7:1.2.3.6;4.4.4.4:4");
Set<IpPort> alts = new IpPortSet();
alts.add(ip);
Set<PushEndpoint> push = new HashSet<PushEndpoint>();
push.add(pe);
MockPong pong = new MockPong(true,true,-1,false,false,false,null,alts,push);
ranker.processMessage(pong, udpReplyHandlerFactory.createUDPReplyHandler(InetAddress.getByName("1.2.3.4"), 1));
// both of the carried altlocs are dupes, so we should not have pinged anybody
assertTrue(pinger.hosts.isEmpty());
}
/**
* Tests that the ranker sends a HeadPing to the push proxies of a firewalled
* source as long as we are not firewalled or can do FWT
*/
public void testPingsFirewalledHosts() throws Exception {
networkManager.setAcceptedIncomingConnection(true);
GUID g = new GUID(GUID.makeGuid());
ranker.addToPool(newPushRFD(g.bytes(),"1.2.2.2:3","2.2.2.3:5"));
assertEquals(1,pinger.hosts.size());
assertIpPortEquals(new IpPortImpl("1.2.2.2",3),pinger.hosts.get(0));
HeadPing ping = (HeadPing)pinger.messages.get(0);
assertEquals(g,ping.getClientGuid());
}
/**
* tests that we do not ping firewalled hosts if we cannot do FWT and are firewalled
*/
public void testSkipsFirewalledHosts() throws Exception {
assertFalse(networkManager.acceptedIncomingConnection());
assertFalse(networkManager.canDoFWT());
GUID g = new GUID(GUID.makeGuid());
ranker.addToPool(newPushRFD(g.bytes(),"1.2.2.2:3","2.2.2.3:5"));
assertEquals(0,pinger.hosts.size());
assertEquals(0,pinger.hosts.size());
}
/**
* We should drop unsolicited pongs.
*/
public void testIgnoresUnsolicitedPongs() throws Exception {
// add a host
ranker.addToPool(newRFDWithURN("1.2.3.4",3));
// receive a pong from another host
MockPong pong = new MockPong(true,true,0,true,false,true,null);
ranker.processMessage(pong, udpReplyHandlerFactory.createUDPReplyHandler(InetAddress.getByName("1.2.3.5"), 1));
// consume the first guy
assertTrue(ranker.hasMore());
ranker.getBest();
// we shouldn't have any more hosts available
assertFalse(ranker.hasMore());
}
/**
* When sending a ping to several push proxies, we may get replies
* from more than one - only one should be processed.
*/
public void testMultipleProxyReplies() throws Exception {
networkManager.setAcceptedIncomingConnection(true);
GUID g = new GUID(GUID.makeGuid());
ranker.addToPool(newPushRFD(g.bytes(),"1.2.2.2:3;1.3.3.3:4","2.2.2.3:5"));
// two pings should be sent out
assertEquals(2,pinger.hosts.size());
Set<IpPort> s = new TreeSet<IpPort>(IpPort.COMPARATOR);
s.addAll(pinger.hosts);
assertTrue(s.contains(new IpPortImpl("1.2.2.2",3)));
assertTrue(s.contains(new IpPortImpl("1.3.3.3",4)));
// receive one pong from each proxy
MockPong pong = new MockPong(true,true,-1,true,false,true,null);
ranker.processMessage(pong, udpReplyHandlerFactory.createUDPReplyHandler(InetAddress.getByName("1.3.3.3"), 4));
ranker.processMessage(pong, udpReplyHandlerFactory.createUDPReplyHandler(InetAddress.getByName("1.2.2.2"), 3));
// there should be only one host available to try
assertTrue(ranker.hasMore());
ranker.getBest();
assertFalse(ranker.hasMore());
}
/**
* Tests that the ranker prefers hosts that have sent a pong back but in
* case it runs out of verified hosts it returns a non-verified one.
*/
public void testPrefersPongedHost() throws Exception {
assertFalse(ranker.hasMore());
List<RemoteFileDescContext> l = new ArrayList<RemoteFileDescContext>(10);
for (int i =0;i < 10;i++)
l.add(newRFDWithURN("1.2.3."+i,3));
ranker.addToPool(l);
assertTrue(ranker.hasMore());
// send a pong back from a single host
MockPong pong = new MockPong(true,true,0,true,false,true,null);
ranker.processMessage(pong, udpReplyHandlerFactory.createUDPReplyHandler(InetAddress.getByName("1.2.3.5"), 1));
// now this host should be prefered over other hosts.
RemoteFileDescContext rfd = ranker.getBest();
assertEquals("1.2.3.5", ((Connectable)rfd.getAddress()).getAddress());
// but if we ask for more hosts we'll get some of the unverified ones
assertTrue(ranker.hasMore());
rfd = ranker.getBest();
assertNotEquals("1.2.3.5", ((Connectable)rfd.getAddress()).getAddress());
assertTrue(((Connectable)rfd.getAddress()).getAddress().startsWith("1.2.3."));
}
/**
* Tests that the ranker discards sources that claim they do not have the file.
* and informs the mesh handler if such exists
*/
public void testDiscardsNoFile() throws Exception {
RemoteFileDescContext noFile = newRFDWithURN("1.2.3.4",3);
ranker.addToPool(noFile);
MockMesh handler = new MockMesh(ranker);
ranker.setMeshHandler(handler);
assertTrue(ranker.hasMore());
MockPong pong = new MockPong(false,true,0,true,false,true,null);
assertFalse(pong.hasFile());
ranker.processMessage(pong, udpReplyHandlerFactory.createUDPReplyHandler(InetAddress.getByName("1.2.3.4"), 1));
assertFalse(ranker.hasMore());
assertEquals(noFile.getRemoteFileDesc(), handler.rfd);
assertFalse(handler.good);
ranker.setMeshHandler(null);
}
/**
* Tests that the ranker offers hosts that indicated they were busy last
*/
public void testBusyOfferedLast() throws Exception {
List<RemoteFileDescContext> l = new ArrayList<RemoteFileDescContext>();
l.add(newRFDWithURN("1.2.3.4",3));
l.add(newRFDWithURN("1.2.3.5",3));
ranker.addToPool(l);
MockPong busy = new MockPong(true,true,20,true,true,true,null);
MockPong notBusy = new MockPong(true,true,0,true,false,true,null);
ranker.processMessage(busy, udpReplyHandlerFactory.createUDPReplyHandler(InetAddress.getByName("1.2.3.4"), 1));
ranker.processMessage(notBusy, udpReplyHandlerFactory.createUDPReplyHandler(InetAddress.getByName("1.2.3.5"), 1));
RemoteFileDescContext best = ranker.getBest();
assertEquals("1.2.3.5", ((Connectable)best.getAddress()).getAddress()); // not busy
best = ranker.getBest();
assertEquals("1.2.3.4", ((Connectable)best.getAddress()).getAddress()); // busy
}
/**
* Tests that the ranker offers hosts that have more free slots first
*/
public void testSortedByQueueRank() throws Exception {
List<RemoteFileDescContext> l = new ArrayList<RemoteFileDescContext>();
l.add(newRFDWithURN("1.2.3.4",3));
l.add(newRFDWithURN("1.2.3.5",3));
l.add(newRFDWithURN("1.2.3.6",3));
ranker.addToPool(l);
MockPong oneFree = new MockPong(true,true,-1,true,false,true,null);
MockPong noFree = new MockPong(true,true,0,true,false,true,null);
MockPong oneQueue = new MockPong(true,true,1,true,false,true,null);
ranker.processMessage(oneQueue,udpReplyHandlerFactory.createUDPReplyHandler(InetAddress.getByName("1.2.3.4"), 1));
ranker.processMessage(oneFree,udpReplyHandlerFactory.createUDPReplyHandler(InetAddress.getByName("1.2.3.5"), 1));
ranker.processMessage(noFree,udpReplyHandlerFactory.createUDPReplyHandler(InetAddress.getByName("1.2.3.6"), 1));
RemoteFileDescContext best = ranker.getBest();
assertEquals("1.2.3.5", ((Connectable)best.getAddress()).getAddress()); // one free slot
best = ranker.getBest();
assertEquals("1.2.3.6", ((Connectable)best.getAddress()).getAddress()); // no free slots
best = ranker.getBest();
assertEquals("1.2.3.4", ((Connectable)best.getAddress()).getAddress()); // one queued
}
/**
* tests that within the same queue rank the firewalled hosts are preferred
* if we can't do fwt
*/
public void testFirewalledPreferred() throws Exception {
networkManager.setAcceptedIncomingConnection(true);
RemoteFileDescContext open = newRFDWithURN("1.2.3.4",3);
RemoteFileDescContext openMoreSlots = newRFDWithURN("1.2.3.5",3);
RemoteFileDescContext push = newPushRFD(GUID.makeGuid(),"1.2.3.6:6",null);
List<RemoteFileDescContext> l = new ArrayList<RemoteFileDescContext>();
l.add(open);l.add(openMoreSlots);l.add(push);
ranker.addToPool(l);
MockPong openPong = new MockPong(true,true,-1,false,false,true,null);
MockPong pushPong = new MockPong(true,true,-1,true,false,true,null);
MockPong openMorePong = new MockPong(true,true,-2,false,false,true,null);
ranker.processMessage(openPong,udpReplyHandlerFactory.createUDPReplyHandler(InetAddress.getByName("1.2.3.4"), 1));
ranker.processMessage(openMorePong,udpReplyHandlerFactory.createUDPReplyHandler(InetAddress.getByName("1.2.3.5"), 1));
ranker.processMessage(pushPong,udpReplyHandlerFactory.createUDPReplyHandler(InetAddress.getByName("1.2.3.6"), 6));
RemoteFileDescContext best = ranker.getBest();
assertEquals("1.2.3.5", ((Connectable)best.getAddress()).getAddress()); // open with more slots
best = ranker.getBest();
assertTrue(((PushEndpoint)best.getAddress()).getProxies().contains(new IpPortImpl("1.2.3.6",6))); // firewalled
best = ranker.getBest();
assertEquals("1.2.3.4", ((Connectable)best.getAddress()).getAddress()); // open
}
/**
* tests that within the same rank and firewall status, partial sources are preferred
*/
public void testPartialPreferred() throws Exception {
networkManager.setAcceptedIncomingConnection(true);
List<RemoteFileDescContext> l = new ArrayList<RemoteFileDescContext>();
l.add(newRFDWithURN("1.2.3.4",3));
l.add(newRFDWithURN("1.2.3.5",3));
l.add(newRFDWithURN("1.2.3.6",3));
l.add(newPushRFD(GUID.makeGuid(),"1.2.3.7:7",null));
ranker.addToPool(l);
MockPong oneFree = new MockPong(true,true,-1,true,false,true,null);
MockPong oneFreePartial = new MockPong(true,false,-1,true,false,true,new IntervalSet());
MockPong noSlotsFull = new MockPong(true,true,0,true,false,true,null);
MockPong oneFreeOpen= new MockPong(true,true,-1,false,false,true,null);
ranker.processMessage(noSlotsFull,udpReplyHandlerFactory.createUDPReplyHandler(InetAddress.getByName("1.2.3.4"), 1));
ranker.processMessage(oneFreeOpen,udpReplyHandlerFactory.createUDPReplyHandler(InetAddress.getByName("1.2.3.5"), 1));
ranker.processMessage(oneFreePartial,udpReplyHandlerFactory.createUDPReplyHandler(InetAddress.getByName("1.2.3.6"), 1));
ranker.processMessage(oneFree,udpReplyHandlerFactory.createUDPReplyHandler(InetAddress.getByName("1.2.3.7"), 7));
RemoteFileDescContext best = ranker.getBest();
assertTrue(((PushEndpoint)best.getAddress()).getProxies().contains(new IpPortImpl("1.2.3.7",7))); // full, firewalled , one slot
best = ranker.getBest();
assertEquals("1.2.3.6", ((Connectable)best.getAddress()).getAddress()); // partial, open, one slot
best = ranker.getBest();
assertEquals("1.2.3.5", ((Connectable)best.getAddress()).getAddress()); // full, open, one slot
best = ranker.getBest();
assertEquals("1.2.3.4", ((Connectable)best.getAddress()).getAddress()); // full, no slots, firewalled
}
/**
* Tests that the ranker offers hosts with low round-trip times first
*/
public void testSortedByRoundTripTime() throws Exception {
List<RemoteFileDescContext> l = new ArrayList<RemoteFileDescContext>();
l.add(newRFDWithURN("1.2.3.4",3));
l.add(newRFDWithURN("1.2.3.5",3));
l.add(newRFDWithURN("1.2.3.6",3));
ranker.addToPool(l);
MockPong oneOneThousand = new MockPong(true,true,-1,true,false,true,null);
MockPong twoOneThousand = new MockPong(true,true,-1,true,false,true,null);
MockPong threeOneThousand = new MockPong(true,true,-1,true,false,true,null);
Thread.sleep(1000);
ranker.processMessage(oneOneThousand,udpReplyHandlerFactory.createUDPReplyHandler(InetAddress.getByName("1.2.3.4"), 1));
Thread.sleep(1000);
ranker.processMessage(twoOneThousand,udpReplyHandlerFactory.createUDPReplyHandler(InetAddress.getByName("1.2.3.5"), 1));
Thread.sleep(1000);
ranker.processMessage(threeOneThousand,udpReplyHandlerFactory.createUDPReplyHandler(InetAddress.getByName("1.2.3.6"), 1));
RemoteFileDescContext best = ranker.getBest();
assertEquals("1.2.3.4", ((Connectable)best.getAddress()).getAddress());
best = ranker.getBest();
assertEquals("1.2.3.5", ((Connectable)best.getAddress()).getAddress());
best = ranker.getBest();
assertEquals("1.2.3.6", ((Connectable)best.getAddress()).getAddress());
}
/**
* Tests that the ranker passes on to other rankers all the hosts it has been
* told or learned about.
*/
public void testGetShareable() throws Exception {
RemoteFileDescContext rfd1, rfd2;
rfd1 = newRFDWithURN("1.2.3.4",3);
rfd2 = newRFDWithURN("1.2.3.5",3);
ranker.addToPool(rfd1);
ranker.addToPool(rfd2);
Collection<RemoteFileDescContext> c = ranker.getShareableHosts();
assertTrue(c.contains(rfd1));
assertTrue(c.contains(rfd2));
assertEquals(2,c.size());
// tell the ranker about some altlocs through a headpong
IpPort ip1, ip2;
ip1 = new IpPortImpl("1.2.3.6",3);
ip2 = new IpPortImpl("1.2.3.7",3);
Set<IpPort> alts = new IpPortSet();
alts.add(ip1);
alts.add(ip2);
MockPong oneFreeOpen= new MockPong(true,true,-1,false,false,true,null,alts, EMPTY_PUSH_ENDPOINT_SET);
ranker.processMessage(oneFreeOpen,udpReplyHandlerFactory.createUDPReplyHandler(InetAddress.getByName("1.2.3.4"), 1));
// the ranker should pass on the altlocs it discovered as well.
c = ranker.getShareableHosts();
assertEquals(4,c.size());
Set<IpPort> s = new IpPortSet();
for (RemoteFileDescContext context : c) {
s.add(((Connectable)context.getAddress()));
}
assertEquals(4,s.size());
assertTrue(s.contains(ip1));
assertTrue(s.contains(ip2));
assertTrue(s.contains(rfd1.getAddress()));
assertTrue(s.contains(rfd2.getAddress()));
}
private RemoteFileDescContext newRFDWithURN(String host, int speed) throws Exception {
Set<URN> set = new HashSet<URN>();
try {
// for convenience, don't require that they pass the urn.
// assume a null one is the TestFile's hash.
set.add(TestFile.hash());
} catch(Exception e) {
fail("SHA1 not created");
}
return toContext(remoteFileDescFactory.createRemoteFileDesc(new ConnectableImpl(host, 1, false), 0, "asdf", TestFile.length(), new byte[16],
speed, 4, false, null, set, false, "", -1));
}
/**
* constructs an rfd for testing. if the host parameter is not null, the
* rfd indicates FWT capability
*/
private RemoteFileDescContext newPushRFD(byte [] guid,String proxy, String hostPort) throws Exception{
GUID g = new GUID(guid);
String s = g.toHexString();
if (hostPort != null)
s = s+";fwt/1.0;" +hostPort.substring(hostPort.indexOf(":")+1)+":"+hostPort.substring(0,hostPort.indexOf(":"));
else
hostPort = "1.1.1.1";
s =s+ ";"+proxy;
PushEndpoint pe = pushEndpointFactory.createPushEndpoint(s);
if (hostPort.contains(":")) {
hostPort = hostPort.substring(0, hostPort.indexOf(":"));
}
RemoteFileDescContext ret = newRFDWithURN(hostPort,3);
ret = new RemoteFileDescContext(remoteFileDescFactory.createRemoteFileDesc(ret.getRemoteFileDesc(), pe));
return ret;
}
/**
* a mock pinger. Note that the base code will still register messsage listeners
* but we don't care because they will never be used.
*/
@Singleton
private static class MockPinger extends UDPPingerImpl {
@Inject
public MockPinger(Provider<MessageRouter> messageRouter, @Named("backgroundExecutor") ScheduledExecutorService scheduledExecutorService,
Provider<UDPService> udpService, PingRequestFactory pingRequestFactory) {
super(messageRouter, scheduledExecutorService, udpService, pingRequestFactory);
}
/**
* the list of messages that was sent
*/
public List<Message> messages = new ArrayList<Message>();
/**
* the list of hosts that we pinged, same order as messages
*/
public List<IpPort> hosts = new ArrayList<IpPort>();
@Override
public void rank(Collection<? extends IpPort> hosts, MessageListener listener,
Cancellable canceller, Message message) {
for(IpPort next : hosts) {
this.hosts.add(next);
messages.add(message);
}
}
}
/**
* a very customizable HeadPong
*/
private class MockPong extends HeadPongImpl {
private Set<IpPort> altLocs;
private Set<PushEndpoint> pushLocs;
private boolean have, full, firewalled, busy, downloading;
private IntervalSet ranges;
private int queueStatus;
public MockPong(boolean have, boolean full, int queueStatus,
boolean firewalled, boolean busy, boolean downloading,
IntervalSet ranges)
throws IOException {
this(have, full, queueStatus, firewalled, busy, downloading, ranges, IpPort.EMPTY_SET, EMPTY_PUSH_ENDPOINT_SET);
}
public MockPong(boolean have, boolean full, int queueStatus,
boolean firewalled, boolean busy, boolean downloading,
IntervalSet ranges, Set<IpPort> altLocs, Set<PushEndpoint> pushLocs)
throws IOException{
super(new GUID(), HeadPong.VERSION, headPongFactory.create(new HeadPing(URN.createSHA1Urn("urn:sha1:PLSTHIPQGSSZTS5FJUPAKUZWUGYQYPFE"))).getPayload());
this.altLocs = altLocs;
this.pushLocs = pushLocs;
this.queueStatus = queueStatus;
this.have = have;
this.full = full;
this.firewalled = firewalled;
this.busy = busy;
this.downloading = downloading;
this.ranges = ranges;
}
@Override
public Set<RemoteFileDesc> getAllLocsRFD(RemoteFileDesc original, RemoteFileDescFactory remoteFileDescFactory) {
Set<RemoteFileDesc> ret = new HashSet<RemoteFileDesc>();
if (altLocs!=null)
for(Iterator iter = altLocs.iterator();iter.hasNext();) {
IpPort current = (IpPort)iter.next();
ret.add(remoteFileDescFactory.createRemoteFileDesc(original, current));
}
if (pushLocs!=null){
for(Iterator iter = pushLocs.iterator();iter.hasNext();) {
PushEndpoint current = (PushEndpoint)iter.next();
ret.add(remoteFileDescFactory.createRemoteFileDesc(original, current));
}
}
return ret;
}
@Override
public Set<IpPort> getAltLocs() {
return this.altLocs;
}
@Override
public Set<PushEndpoint> getPushLocs() {
return pushLocs;
}
@Override
public int getQueueStatus() {
return queueStatus;
}
@Override
public IntervalSet getRanges() {
return ranges;
}
@Override
public boolean hasCompleteFile() {
return full;
}
@Override
public boolean hasFile() {
return have;
}
@Override
public boolean isBusy() {
return busy;
}
@Override
public boolean isDownloading() {
return downloading;
}
@Override
public boolean isFirewalled() {
return firewalled;
}
@Override
public boolean isRoutingBroken() {
return true;
}
}
private static void assertIpPortEquals(IpPort a, IpPort b) {
assertTrue(IpPort.COMPARATOR.compare(a,b) == 0);
}
private RemoteFileDescContext toContext(RemoteFileDesc rfd) {
RemoteFileDescContext newContext = new RemoteFileDescContext(rfd);
RemoteFileDescContext oldContext = contexts.putIfAbsent(rfd, newContext);
return oldContext != null ? oldContext : newContext;
}
private Collection<RemoteFileDescContext> toContexts(Collection<? extends RemoteFileDesc> hosts) {
List<RemoteFileDescContext> list = new ArrayList<RemoteFileDescContext>();
for (RemoteFileDesc host : hosts) {
list.add(toContext(host));
}
return list;
}
private class MockMesh implements MeshHandler {
private final SourceRanker ranker;
public MockMesh(SourceRanker ranker) {
this.ranker = ranker;
}
public boolean good;
public RemoteFileDesc rfd;
public Collection<? extends RemoteFileDesc> sources;
public void informMesh(RemoteFileDesc rfd, boolean good) {
this.rfd = rfd;
this.good = good;
}
@Override
public void addPossibleSources(Collection<? extends RemoteFileDesc> c) {
sources = c;
ranker.addToPool(toContexts(c));
}
}
}