package org.limewire.mojito.handler.request;
import java.net.InetSocketAddress;
import java.util.concurrent.ExecutionException;
import junit.framework.TestSuite;
import org.limewire.mojito.Context;
import org.limewire.mojito.MojitoDHT;
import org.limewire.mojito.MojitoFactory;
import org.limewire.mojito.MojitoTestCase;
import org.limewire.mojito.exceptions.DHTException;
import org.limewire.mojito.result.PingResult;
import org.limewire.mojito.settings.ContextSettings;
import org.limewire.mojito.settings.NetworkSettings;
import org.limewire.mojito.util.UnitTestUtils;
public class PingRequestHandlerTest extends MojitoTestCase {
public PingRequestHandlerTest(String name) {
super(name);
}
public static TestSuite suite() {
return buildTestSuite(PingRequestHandlerTest.class);
}
public static void main(String[] args) {
junit.textui.TestRunner.run(suite());
}
@Override
protected void setUp() throws Exception {
super.setUp();
setLocalIsPrivate(false);
}
public void testPingRequest() throws Exception {
final long waitForFutureDone = 250; // ms
NetworkSettings.MAX_ERRORS.setValue(0);
NetworkSettings.DEFAULT_TIMEOUT.setValue(250);
MojitoDHT dht1 = null;
MojitoDHT dht2 = null;
try {
dht1 = MojitoFactory.createDHT();
dht1.bind(2000);
dht1.start();
dht2 = MojitoFactory.createDHT();
dht2.bind(3000);
dht2.start();
// Regular Ping
try {
PingResult result = dht2.ping(new InetSocketAddress("localhost", 2000)).get();
assertNotNull(result);
} catch (ExecutionException err) {
fail(err);
}
// FutureTask.get() returns before FutureTask.done()
// is called. We use the done() method internally to
// deregister ping tasks. If done() doesn't get called
// before we're doing out next ping it will return the
// same Future handle (i.e. there's no ping sent!)...
Thread.sleep(waitForFutureDone);
// A Node that's bootstrapping should not respond to
// Pings to prevent other Nodes from selecting it as
// their initial bootstrap Node
Context context1 = (Context)dht1;
UnitTestUtils.setBootstrapping(dht1, true);
assertFalse(dht1.isBootstrapped());
assertTrue(dht1.isBootstrapping());
try {
PingResult result = dht2.ping(new InetSocketAddress("localhost", 2000)).get();
assertFalse(dht1.isBootstrapped());
assertTrue(dht1.isBootstrapping());
fail("DHT-1 did respond to our request " + result);
} catch (ExecutionException expected) {
assertTrue(expected.getCause() instanceof DHTException);
}
Thread.sleep(waitForFutureDone);
// next collision Ping. Different Node IDs -> should not work (same as above)
context1.setContactAddress(new InetSocketAddress("localhost", 2000));
Context context2 = (Context)dht2;
// Disable local assertion to make sure the network level
// collision ping checks work
ContextSettings.ASSERT_COLLISION_PING.setValue(false);
try {
PingResult result = context2.collisionPing(dht1.getLocalNode()).get();
fail("DHT-1 did respond to our request " + result);
} catch (ExecutionException expected) {
assertTrue(expected.getCause() instanceof DHTException);
} catch (IllegalArgumentException err) {
fail("Should not have thrown an IllegalArgumentException", err);
}
Thread.sleep(waitForFutureDone);
// Re-Enable local assertion to make sure you can't create
// malformed collision pings like above
ContextSettings.ASSERT_COLLISION_PING.setValue(true);
try {
PingResult result = context2.collisionPing(dht1.getLocalNode()).get();
fail("DHT-1 did respond to our request " + result);
} catch (ExecutionException expected) {
assertTrue(expected.getCause() instanceof DHTException);
} catch (IllegalArgumentException expected) {
}
Thread.sleep(waitForFutureDone);
// Set DHT-2's Node ID to DHT-1 and try again. This should work!
UnitTestUtils.setNodeID(dht2, dht1.getLocalNodeID());
try {
PingResult result = context2.collisionPing(dht1.getLocalNode()).get();
assertNotNull(result);
} catch (ExecutionException err) {
fail(err);
}
// Make sure DHT-1 is still bootstrapping!
assertFalse(dht1.isBootstrapped());
assertTrue(context1.isBootstrapping());
} finally {
if (dht1 != null) { dht1.close(); }
if (dht2 != null) { dht2.close(); }
}
}
}