package com.limegroup.gnutella;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import junit.framework.Test;
import com.limegroup.gnutella.handshaking.LeafHeaders;
import com.limegroup.gnutella.handshaking.UltrapeerHeaders;
import com.limegroup.gnutella.messages.Message;
import com.limegroup.gnutella.messages.PingReply;
import com.limegroup.gnutella.messages.PingRequest;
import com.limegroup.gnutella.routing.QueryRouteTable;
import com.limegroup.gnutella.routing.RouteTableMessage;
import com.limegroup.gnutella.settings.ApplicationSettings;
import com.limegroup.gnutella.settings.ConnectionSettings;
import com.limegroup.gnutella.settings.FilterSettings;
import com.limegroup.gnutella.settings.PingPongSettings;
import com.limegroup.gnutella.settings.UltrapeerSettings;
import com.limegroup.gnutella.stubs.ActivityCallbackStub;
import com.limegroup.gnutella.util.BaseTestCase;
import com.limegroup.gnutella.util.EmptyResponder;
/**
* This test makes sure that pong caching is working correctly between
* Ultrapeers.
*
* ULTRAPEER_1 ---- CENTRAL TEST ULTRAPEER ---- ULTRAPEER_2
* |
* |
* |
* LEAF
*/
public final class PongCachingTest extends BaseTestCase {
/**
* The port that the central Ultrapeer listens on, and that the other nodes
* connect to it on.
*/
private static final int SERVER_PORT = 6667;
/**
* The timeout value for sockets -- how much time we wait to accept
* individual messages before giving up.
*/
private static final int TIMEOUT = 1800;
/**
* Leaf connection to the Ultrapeer.
*/
private Connection LEAF;
/**
* Ultrapeer connection.
*/
private Connection ULTRAPEER_1;
/**
* Second Ultrapeer connection
*/
private Connection ULTRAPEER_2;
/**
* Third Ultrapeer connection
*/
private Connection ULTRAPEER_3;
/**
* Fourth Ultrapeer connection
*/
private Connection ULTRAPEER_4;
/**
* The central Ultrapeer used in the test.
*/
private static final RouterService ROUTER_SERVICE =
new RouterService(new ActivityCallbackStub());
public PongCachingTest(String name) {
super(name);
}
public static Test suite() {
return buildTestSuite(PongCachingTest.class);
}
public static void main(String[] args) {
junit.textui.TestRunner.run(suite());
}
private void buildConnections() {
LEAF = new Connection("localhost", SERVER_PORT);
ULTRAPEER_1 = new Connection("localhost", SERVER_PORT);
ULTRAPEER_2 = new Connection("localhost", SERVER_PORT);
ULTRAPEER_3 = new Connection("localhost", SERVER_PORT);
ULTRAPEER_4 = new Connection("localhost", SERVER_PORT);
}
public void setUp() throws Exception {
//Setup LimeWire backend. For testing other vendors, you can skip all
//this and manually configure a client to listen on port 6667, with
//incoming slots and no connections.
//To keep LimeWire from connecting to the outside network, we filter out
//all addresses but localhost and 18.239.0.*. The latter is used in
//pongs for testing. TODO: it would be nice to have a way to prevent
//BootstrapServerManager from adding defaults and connecting.
FilterSettings.BLACK_LISTED_IP_ADDRESSES.setValue(
new String[] {"*.*.*.*"});
FilterSettings.WHITE_LISTED_IP_ADDRESSES.setValue(
new String[] {"127.*.*.*", "18.239.0.*"});
ConnectionSettings.PORT.setValue(SERVER_PORT);
setSharedDirectories(new File[0]);
ConnectionSettings.CONNECT_ON_STARTUP.setValue(false);
UltrapeerSettings.EVER_ULTRAPEER_CAPABLE.setValue(true);
UltrapeerSettings.DISABLE_ULTRAPEER_MODE.setValue(false);
UltrapeerSettings.FORCE_ULTRAPEER_MODE.setValue(true);
UltrapeerSettings.MAX_LEAVES.setValue(4);
ConnectionSettings.NUM_CONNECTIONS.setValue(3);
ConnectionSettings.LOCAL_IS_PRIVATE.setValue(false);
ConnectionSettings.USE_GWEBCACHE.setValue(false);
ConnectionSettings.WATCHDOG_ACTIVE.setValue(false);
ConnectionSettings.SEND_QRP.setValue(false);
UltrapeerSettings.NEED_MIN_CONNECT_TIME.setValue(false);
assertEquals("unexpected port", SERVER_PORT,
ConnectionSettings.PORT.getValue());
ROUTER_SERVICE.start();
RouterService.clearHostCatcher();
RouterService.connect();
connect();
assertEquals("unexpected port", SERVER_PORT,
ConnectionSettings.PORT.getValue());
}
public void tearDown() throws Exception {
drainAll();
sleep();
LEAF.close();
ULTRAPEER_1.close();
ULTRAPEER_2.close();
ULTRAPEER_3.close();
ULTRAPEER_4.close();
ConnectionSettings.SEND_QRP.setValue(true);
RouterService.disconnect();
sleep();
}
private void sleep() {
try {Thread.sleep(300);}catch(InterruptedException e) {}
}
/**
* Drains all messages
*/
private void drainAll() throws Exception {
if(ULTRAPEER_1.isOpen()) {
drain(ULTRAPEER_1, TIMEOUT);
}
if(ULTRAPEER_2.isOpen()) {
drain(ULTRAPEER_2, TIMEOUT);
}
if(ULTRAPEER_3.isOpen()) {
drain(ULTRAPEER_3, TIMEOUT);
}
if(ULTRAPEER_4.isOpen()) {
drain(ULTRAPEER_4, TIMEOUT);
}
if(LEAF.isOpen()) {
drain(LEAF, TIMEOUT);
}
}
/**
* Connects all of the nodes to the central test Ultrapeer.
*/
private void connect() throws Exception {
buildConnections();
//1. first Ultrapeer connection
ULTRAPEER_2.initialize(new UltrapeerHeaders("localhost"), new EmptyResponder());
assertTrue("should be open", ULTRAPEER_2.isOpen());
assertTrue("should be up", ULTRAPEER_2.isSupernodeSupernodeConnection());
ULTRAPEER_3.initialize(new UltrapeerHeaders("localhost"), new EmptyResponder());
assertTrue("should be open", ULTRAPEER_3.isOpen());
assertTrue("should be up", ULTRAPEER_3.isSupernodeSupernodeConnection());
ULTRAPEER_4.initialize(new UltrapeerHeaders("localhost"), new EmptyResponder());
assertTrue("should be open", ULTRAPEER_4.isOpen());
assertTrue("should be up", ULTRAPEER_4.isSupernodeSupernodeConnection());
//2. second Ultrapeer connection
ULTRAPEER_1.initialize(new UltrapeerHeaders("localhost"), new EmptyResponder());
assertTrue("should be open", ULTRAPEER_1.isOpen());
assertTrue("should be up", ULTRAPEER_1.isSupernodeSupernodeConnection());
//3. routed leaf, with route table for "test"
LEAF.initialize(new LeafHeaders("localhost"), new EmptyResponder());
assertTrue("should be open", LEAF.isOpen());
assertTrue("should be up", LEAF.isClientSupernodeConnection());
QueryRouteTable qrt = new QueryRouteTable();
qrt.add("test");
qrt.add("susheel");
qrt.addIndivisible(HugeTestUtils.UNIQUE_SHA1.toString());
for (Iterator iter=qrt.encode(null).iterator(); iter.hasNext(); ) {
LEAF.send((RouteTableMessage)iter.next());
LEAF.flush();
}
// for Ultrapeer 1
qrt = new QueryRouteTable();
qrt.add("leehsus");
qrt.add("awesome");
for (Iterator iter=qrt.encode(null).iterator(); iter.hasNext(); ) {
ULTRAPEER_1.send((RouteTableMessage)iter.next());
ULTRAPEER_1.flush();
}
// make sure we get rid of any initial ping pong traffic exchanges
sleep();
drainAll();
}
/**
* Tests to make sure that pongs are received properly via
* pong caching.
*/
public void testPongsReceivedFromPing() throws Exception {
PingPongSettings.PINGS_ACTIVE.setValue(false);
byte[] ip = { (byte)1, (byte)2, (byte)3, (byte)4 };
for(int i=0; i<PongCacher.NUM_HOPS+4; i++) {
PingReply curPong =
PingReply.create(new GUID().bytes(), (byte)3, 13232, ip, 0, 0,
true, -1, false);
for(int j=0; j<i; j++) {
if(j < PongCacher.NUM_HOPS) {
curPong.hop();
}
}
PongCacher.instance().addPong(curPong);
}
List pongs = PongCacher.instance()
.getBestPongs(ApplicationSettings.LANGUAGE.getValue());
assertEquals( PongCacher.NUM_HOPS, pongs.size() );
Message m = new PingRequest((byte)7);
ULTRAPEER_1.send(m);
ULTRAPEER_1.flush();
Message received;
for(int i=0; i<PongCacher.NUM_HOPS; i++) {
received = getFirstMessageOfType(ULTRAPEER_1, PingReply.class, 10000);
assertNotNull("should have gotten pong. hop: " + i, received);
}
PingPongSettings.PINGS_ACTIVE.setValue(true);
}
/**
* Tests to make sure that pongs are received properly via
* pong caching when the locale is specified in the ping
*/
public void testPongsReceivedFromPingWithLocale() throws Exception {
PingPongSettings.PINGS_ACTIVE.setValue(false);
byte[] ip = { (byte)1, (byte)2, (byte)3, (byte)3 };
//add english locale pongs
for(int i=0; i<PongCacher.NUM_HOPS+4; i++) {
PingReply curPong =
PingReply.create(new GUID().bytes(), (byte)3, 13232, ip, 0, 0,
true, -1, false, "en", 1);
for(int j=0; j<i; j++) {
if(j < PongCacher.NUM_HOPS) {
curPong.hop();
}
}
PongCacher.instance().addPong(curPong);
}
byte[] ip2 = { (byte)1, (byte)3, (byte)3, (byte)3 };
//add ja locale pongs
for(int i=0; i<PongCacher.NUM_HOPS+4; i++) {
PingReply curPong =
PingReply.create(new GUID().bytes(), (byte)3, 13232, ip2,
0, 0, true, -1, false, "ja", 1);
for(int j=0; j<i; j++) {
if(j < PongCacher.NUM_HOPS) {
curPong.hop();
}
}
PongCacher.instance().addPong(curPong);
}
//check that all the pongs are in the PongCacher
List pongs = PongCacher.instance().getBestPongs("ja");
assertEquals( PongCacher.NUM_HOPS, pongs.size() );
pongs = PongCacher.instance().getBestPongs("en");
assertEquals( PongCacher.NUM_HOPS, pongs.size() );
//create a ja locale PingRequest
ApplicationSettings.LANGUAGE.setValue("ja");
Message m = new PingRequest((byte)7);
assertEquals("locale of ping should be ja",
"ja", ((PingRequest)m).getLocale());
//send a ja ping using ULTRAPEER_3
ULTRAPEER_3.send(m);
ULTRAPEER_3.flush();
Thread.sleep(100);
ApplicationSettings.LANGUAGE.setValue("en");
//check for ja pongs
Message received;
for(int i=0; i< PongCacher.NUM_HOPS; i++) {
received = getFirstMessageOfType(ULTRAPEER_3,
PingReply.class,
5000);
assertNotNull("should have gotten pong. hop: " + i, received);
PingReply pr = (PingReply)received;
assertEquals("should be a ja locale pong ",
"ja", pr.getClientLocale());
}
byte[] ip3 = { (byte)3, (byte)3, (byte)3, (byte)3 };
//add sv locale pongs
for(int i=0; i< 2; i++) {
PingReply curPong =
PingReply.create(new GUID().bytes(), (byte)3, 13232, ip3,
0, 0, true, -1, false, "sv", 1);
for(int j=0; j<i; j++) {
if(j < PongCacher.NUM_HOPS) {
curPong.hop();
}
}
PongCacher.instance().addPong(curPong);
}
pongs = PongCacher.instance().getBestPongs("sv");
assertEquals( PongCacher.NUM_HOPS, pongs.size() );
//create a sv locale PingRequest
ApplicationSettings.LANGUAGE.setValue("sv");
Message m2 = new PingRequest((byte)7);
assertEquals("locale of ping should be sv",
"sv", ((PingRequest)m2).getLocale());
ULTRAPEER_4.send(m2);
ULTRAPEER_4.flush();
//check ofr sv pongs
List returnedPongs = new ArrayList();
for(int i = 0; i < PongCacher.NUM_HOPS; i++) {
received = getFirstMessageOfType(ULTRAPEER_4,
PingReply.class,
5000);
assertNotNull("should have gotten pong. hop: " + i, received);
PingReply pr = (PingReply)received;
returnedPongs.add(pr);
}
//check that there are two "sv" pongs and the rest are
//"en" - the default locale
int numSVPongs = 0;
Iterator iter = returnedPongs.iterator();
while(iter.hasNext()) {
PingReply pr = (PingReply)iter.next();
if(pr.getClientLocale().equals("sv"))
numSVPongs++;
else
assertEquals("the locale of pong should be en : ",
"en", pr.getClientLocale());
}
assertEquals("there should of been two pongs with the locale of sv : ",
2, numSVPongs);
PingPongSettings.PINGS_ACTIVE.setValue(true);
}
}