package com.limegroup.gnutella; import java.net.InetAddress; import java.util.Iterator; import java.util.List; import java.util.Map; import junit.framework.Test; import com.limegroup.gnutella.messages.PingReply; import com.limegroup.gnutella.settings.ApplicationSettings; import com.limegroup.gnutella.util.BaseTestCase; import com.limegroup.gnutella.util.BucketQueue; import com.limegroup.gnutella.util.MessageTestUtils; import com.limegroup.gnutella.util.PrivilegedAccessor; import com.limegroup.gnutella.util.UltrapeerConnectionManager; /** * Tests the <tt>PongCacher</tt> class that maintains a cache of the best most * recent pongs seen. */ public final class PongCacherTest extends BaseTestCase { private static final PongCacher PC = PongCacher.instance(); public PongCacherTest(String name) { super(name); } public static Test suite() { return buildTestSuite(PongCacherTest.class); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public void setUp() throws Exception { Map m = (Map)PrivilegedAccessor.getValue(PC, "PONGS"); if(m != null) m.clear(); } public static void globalSetUp() throws Exception { RouterService.getAcceptor().setAddress(InetAddress.getLocalHost()); } /** * Test to make sure that expiring of pongs is working correctly. * @throws Exception */ public void testPongExpiring() throws Exception { // Trick us into thinking we're an Ultrapeer. PrivilegedAccessor.setValue(RouterService.class, "manager", new TestManager()); // Create a pong with the correct GGEP for our cacher to accept it. PingReply pr = MessageTestUtils.createPongWithFreeLeafSlots(); PongCacher.instance().addPong(pr); // Make sure we get the pong successfully. List pongs = PongCacher.instance() .getBestPongs(ApplicationSettings.LANGUAGE.getValue()); 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.instance() .getBestPongs(ApplicationSettings.LANGUAGE.getValue()); 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. PingReply pr2 = MessageTestUtils.createPongWithFreeLeafSlots(); pr2.hop(); PongCacher.instance().addPong(pr2); // Make sure we get the 2 pongs successfully in the correct order. pongs = PongCacher.instance().getBestPongs(ApplicationSettings.DEFAULT_LOCALE.getValue()); 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.instance() .getBestPongs(ApplicationSettings.LANGUAGE.getValue()); assertEquals("list should be empty", 0, pongs.size()); } /** * Tests the method for getting the best set of pongs. */ public void testGetBestPongs() throws Exception { ConnectionManager cm = new UltrapeerConnectionManager(); PrivilegedAccessor.setValue(RouterService.class, "manager", cm); List pongs = PC.getBestPongs(ApplicationSettings.LANGUAGE.getValue()); PingReply pong = PingReply.create(new GUID().bytes(), (byte)5); PC.addPong(pong); pongs = PC.getBestPongs(ApplicationSettings.LANGUAGE.getValue()); assertEquals("unexpected number of cached pongs", 1, pongs.size()); pong = PingReply.create(new GUID().bytes(), (byte)5); PC.addPong(pong); pongs = PC.getBestPongs(ApplicationSettings.LANGUAGE.getValue()); 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 = PingReply.create(new GUID().bytes(), (byte)5); PC.addPong(curPong); } pongs = PC.getBestPongs(ApplicationSettings.LANGUAGE.getValue()); assertEquals("unexpected number of cached pongs", PongCacher.NUM_PONGS_PER_HOP, pongs.size()); PingReply highHopPong = PingReply.create(new GUID().bytes(), (byte)5); highHopPong.hop(); highHopPong.hop(); PC.addPong(highHopPong); //Thread.sleep(PongCacher.REFRESH_INTERVAL+200); pongs = PC.getBestPongs(ApplicationSettings.LANGUAGE.getValue()); 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 = PingReply.create(new GUID().bytes(), (byte)5); highHopPong2.hop(); highHopPong2.hop(); highHopPong2.hop(); highHopPong2.hop(); PC.addPong(highHopPong2); //Thread.sleep(PongCacher.REFRESH_INTERVAL+200); pongs = PC.getBestPongs(ApplicationSettings.LANGUAGE.getValue()); 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 { ConnectionManager cm = new UltrapeerConnectionManager(); PrivilegedAccessor.setValue(RouterService.class, "manager", cm); PingReply pong = PingReply.create(new GUID().bytes(), (byte)5); PC.addPong(pong); Map m = (Map)PrivilegedAccessor.getValue(PongCacher.class, "PONGS"); BucketQueue bq = (BucketQueue)m.get(pong.getClientLocale()); assertEquals("unexpected bucket queue size", 1, bq.size()); pong = PingReply.create(new GUID().bytes(), (byte)5); PC.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++) { PC.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 { // Trick us into thinking we're an Ultrapeer. PrivilegedAccessor.setValue(RouterService.class, "manager", new TestManager()); // Create a pong with the correct GGEP for our cacher to accept it. PingReply pr = MessageTestUtils.createPongWithFreeLeafSlots(); PrivilegedAccessor.setValue((Object)pr, "CLIENT_LOCALE", "en"); PrivilegedAccessor.setValue((Object)pr, "hops", new Byte((byte)1)); PongCacher.instance().addPong(pr); PingReply prj = MessageTestUtils.createPongWithFreeLeafSlots(); PrivilegedAccessor.setValue((Object)prj, "CLIENT_LOCALE", "ja"); PrivilegedAccessor.setValue((Object)prj, "hops", new Byte((byte)1)); PongCacher.instance().addPong(prj); PingReply prj2 = MessageTestUtils.createPongWithFreeLeafSlots(); PrivilegedAccessor.setValue((Object)prj2, "CLIENT_LOCALE", "ja"); PrivilegedAccessor.setValue((Object)prj2, "hops", new Byte((byte)2)); PongCacher.instance().addPong(prj2); //should only return en (en) List pongs = PongCacher.instance().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.instance().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.instance().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"); } private static class TestManager extends ConnectionManager { public TestManager() { super(); } public boolean isSupernode() { return true; } } }