package com.limegroup.gnutella;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import junit.framework.Test;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.limewire.collection.BucketQueue;
import org.limewire.core.settings.ApplicationSettings;
import org.limewire.gnutella.tests.LimeTestCase;
import com.limegroup.gnutella.messages.PingReply;
import com.limegroup.gnutella.util.MessageTestUtils;
/**
* Tests the <tt>PongCacher</tt> class that maintains a cache of the best most
* recent pongs seen.
*/
public final class PongCacherImplTest extends LimeTestCase {
private PongCacherImpl pongCacher;
private Mockery context;
private ConnectionServices connectionServices;
public PongCacherImplTest(String name) {
super(name);
}
public static Test suite() {
return buildTestSuite(PongCacherImplTest.class);
}
public static void main(String[] args) {
junit.textui.TestRunner.run(suite());
}
@Override
public void setUp() throws Exception {
context = new Mockery();
connectionServices = context.mock(ConnectionServices.class);
pongCacher = new PongCacherImpl(connectionServices);
// all test cases expect us to be an ultrapeer
context.checking(new Expectations() {{
allowing(connectionServices).isSupernode();
will(returnValue(true));
}});
}
/**
* Test to make sure that expiring of pongs is working correctly.
* @throws Exception
*/
public void testPongExpiring() throws Exception {
// Create a pong with the correct GGEP for our cacher to accept it.
PingReply pr = context.mock(PingReply.class);
MessageTestUtils.mockPongWithFreeLeafSlots(context, pr);
pongCacher.addPong(pr);
// Make sure we get the pong successfully.
List pongs = pongCacher.getBestPongs(ApplicationSettings.LANGUAGE.get());
assertEquals("should be 1 pong",1,pongs.size());
Iterator iter = pongs.iterator();
PingReply retrievedPong = (PingReply)iter.next();
assertEquals("unexpected pong", pr, retrievedPong);
// Make sure we still get the pong successfully on a second pass.
pongs = pongCacher.getBestPongs(ApplicationSettings.LANGUAGE.get());
assertEquals("should be 1 pong",1,pongs.size());
iter = pongs.iterator();
retrievedPong = (PingReply)iter.next();
assertEquals("unexpected pong", pr, retrievedPong);
// Create a second pong with the correct GGEP for our cacher
// to accept it.
final PingReply pr2 = context.mock(PingReply.class);
context.checking(new Expectations() {{
allowing(pr2).getHops();
will(returnValue((byte)1));
}});
MessageTestUtils.mockPongWithFreeLeafSlots(context, pr2);
pongCacher.addPong(pr2);
// Make sure we get the 2 pongs successfully in the correct order.
pongs = pongCacher.getBestPongs(ApplicationSettings.DEFAULT_LOCALE.get());
assertEquals("should be 2 pongs",2,pongs.size());
assertContains("no p2", pongs, pr2);
assertContains("no p", pongs, pr);
// Finally, make sure the pong expires on a sleep -- add a bit to the
// sleep to avoid thread scheduling craziness.
Thread.sleep(PongCacher.EXPIRE_TIME+800);
pongs = pongCacher.getBestPongs(ApplicationSettings.LANGUAGE.get());
assertEquals("list should be empty", 0, pongs.size());
}
private PingReply createPong(final int ttl, final int hops) {
final PingReply pingReply = context.mock(PingReply.class);
context.checking(new Expectations() {{
allowing(pingReply).getTTL();
will(returnValue((byte)ttl));
allowing(pingReply).getHops();
will(returnValue((byte)hops));
}});
MessageTestUtils.mockPongWithFreeLeafSlots(context, pingReply);
return pingReply;
}
private PingReply createLocalePong(final String locale, final int hops) {
final PingReply pingReply = context.mock(PingReply.class);
context.checking(new Expectations() {{
atLeast(1).of(pingReply).getClientLocale();
will(returnValue(locale));
allowing(pingReply).getHops();
will(returnValue((byte)hops));
}});
MessageTestUtils.mockPongWithFreeLeafSlots(context, pingReply);
return pingReply;
}
/**
* Tests the method for getting the best set of pongs.
*/
public void testGetBestPongs() throws Exception {
List pongs = pongCacher.getBestPongs(ApplicationSettings.LANGUAGE.get());
PingReply pong = createPong(5, 0);
pongCacher.addPong(pong);
pongs = pongCacher.getBestPongs(ApplicationSettings.LANGUAGE.get());
assertEquals("unexpected number of cached pongs",
1, pongs.size());
pong = createPong(5, 0);
pongCacher.addPong(pong);
pongs = pongCacher.getBestPongs(ApplicationSettings.LANGUAGE.get());
assertEquals("unexpected number of cached pongs",
1, pongs.size());
// fill up the pongs at the default hop
for(int i=0; i<30; i++) {
PingReply curPong = createPong(5, 0);
pongCacher.addPong(curPong);
}
pongs = pongCacher.getBestPongs(ApplicationSettings.LANGUAGE.get());
assertEquals("unexpected number of cached pongs",
PongCacher.NUM_PONGS_PER_HOP, pongs.size());
PingReply highHopPong = createPong(3, 2);
pongCacher.addPong(highHopPong);
//Thread.sleep(PongCacher.REFRESH_INTERVAL+200);
pongs = pongCacher.getBestPongs(ApplicationSettings.LANGUAGE.get());
assertEquals("unexpected number of cached pongs",
PongCacher.NUM_PONGS_PER_HOP+1, pongs.size());
Iterator iter = pongs.iterator();
PingReply pr = (PingReply)iter.next();
assertEquals("first pong should be high hops", highHopPong, pr);
PingReply highHopPong2 = createPong(1, 4);
pongCacher.addPong(highHopPong2);
//Thread.sleep(PongCacher.REFRESH_INTERVAL+200);
pongs = pongCacher.getBestPongs(ApplicationSettings.LANGUAGE.get());
assertEquals("unexpected number of cached pongs",
PongCacher.NUM_PONGS_PER_HOP+2, pongs.size());
iter = pongs.iterator();
pr = (PingReply)iter.next();
assertEquals("first pong should be high hops", highHopPong2, pr);
}
/**
* Tests the method for adding a pong to the cacher.
*/
public void testAddPong() throws Exception {
PingReply pong = createPong(5, 0);
pongCacher.addPong(pong);
Map<String, BucketQueue<PingReply>> m = pongCacher.getPongMap();
BucketQueue bq = m.get(pong.getClientLocale());
assertEquals("unexpected bucket queue size", 1, bq.size());
pong = createPong(5, 0);
pongCacher.addPong(pong);
assertEquals("unexpected bucket queue size", 1, bq.size());
assertEquals("unexpected bucket queue size", 1, bq.size(0));
for(int i=bq.size(0); i<PongCacher.NUM_PONGS_PER_HOP+2; i++) {
pongCacher.addPong(pong);
}
assertEquals("unexpected bucket queue size",
PongCacher.NUM_PONGS_PER_HOP, bq.size(0));
}
/**
* Tests the locale preferencing of PongCacher.
*/
public void testLocalePong() throws Exception {
// Create a pong with the correct GGEP for our cacher to accept it.
PingReply pr = createLocalePong("en", 1);
pongCacher.addPong(pr);
PingReply prj = createLocalePong("ja", 1);
pongCacher.addPong(prj);
PingReply prj2 = createLocalePong("ja", 2);
pongCacher.addPong(prj2);
// should only return en (en)
List pongs = pongCacher.getBestPongs("en");
assertEquals("unexpected size returned from PongCacher when asking for en locale pongs",
1, pongs.size());
assertEquals("pong's locale doesn't match",
((PingReply)pongs.get(0)).getClientLocale(),
"en");
// should return "ja" pongs in the beggining (ja, ja, en)
pongs = pongCacher.getBestPongs("ja");
assertEquals("unexpected size returned from PongCacher when asking for ja locale pongs",
3, pongs.size());
assertEquals("pong's locale doesn't match",
((PingReply)pongs.get(0)).getClientLocale(),
"ja");
assertEquals("pong's locale doesn't match",
((PingReply)pongs.get(1)).getClientLocale(),
"ja");
assertEquals("pong's locale doesn't match",
((PingReply)pongs.get(2)).getClientLocale(),
"en");
//expire default locale pong but the "ja" locale pongs should be
//around
Thread.sleep(PongCacher.EXPIRE_TIME+800);
pongs = pongCacher.getBestPongs("ja");
assertEquals("unexpected size returned from PongCacher when asking for ja locale pongs",
2, pongs.size());
assertEquals("pong's locale doesn't match",
((PingReply)pongs.get(0)).getClientLocale(),
"ja");
assertEquals("pong's locale doesn't match",
((PingReply)pongs.get(1)).getClientLocale(),
"ja");
}
}