package com.limegroup.gnutella.bootstrap;
import static com.limegroup.gnutella.bootstrap.BootstrapperImpl.MULTICAST_INTERVAL;
import static com.limegroup.gnutella.bootstrap.BootstrapperImpl.TCP_FALLBACK_DELAY;
import static com.limegroup.gnutella.bootstrap.BootstrapperImpl.TCP_INTERVAL;
import static com.limegroup.gnutella.bootstrap.BootstrapperImpl.UDP_FALLBACK_DELAY;
import static com.limegroup.gnutella.bootstrap.BootstrapperImpl.UDP_INTERVAL;
import junit.framework.Test;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.limewire.core.settings.ConnectionSettings;
import org.limewire.util.BaseTestCase;
import com.google.inject.Provider;
import com.limegroup.gnutella.ConnectionServices;
import com.limegroup.gnutella.MulticastService;
import com.limegroup.gnutella.messages.PingRequest;
import com.limegroup.gnutella.messages.PingRequestFactory;
public class BootstrapperImplTest extends BaseTestCase {
Mockery context;
ConnectionServices connectionServices;
MulticastService multicastService;
PingRequestFactory pingRequestFactory;
Bootstrapper.Listener listener;
TcpBootstrap tcpBootstrap;
UDPHostCache udpHostCache;
PingRequest pingRequest;
BootstrapperImpl bootstrapper;
public BootstrapperImplTest(String name) {
super(name);
}
public static Test suite() {
return buildTestSuite(BootstrapperImplTest.class);
}
@Override
public void setUp() {
// Reduce the timing constants so the tests run faster
MULTICAST_INTERVAL /= 10;
TCP_FALLBACK_DELAY /= 10;
TCP_INTERVAL /= 10;
UDP_FALLBACK_DELAY /= 10;
UDP_INTERVAL /= 10;
ConnectionSettings.BOOTSTRAP_DELAY.setValue(
ConnectionSettings.BOOTSTRAP_DELAY.getValue() / 10);
context = new Mockery();
connectionServices = context.mock(ConnectionServices.class);
multicastService = context.mock(MulticastService.class);
Provider<MulticastService> mcast = new Provider<MulticastService>() {
@Override
public MulticastService get() {
return multicastService;
}
};
pingRequestFactory = context.mock(PingRequestFactory.class);
listener = context.mock(Bootstrapper.Listener.class);
tcpBootstrap = context.mock(TcpBootstrap.class);
udpHostCache = context.mock(UDPHostCache.class);
pingRequest = context.mock(PingRequest.class);
bootstrapper = new BootstrapperImpl(connectionServices,
mcast, pingRequestFactory, listener, tcpBootstrap,
udpHostCache);
ConnectionSettings.DO_NOT_MULTICAST_BOOTSTRAP.setValue(false);
}
@Override
public void tearDown() {
// Restore the timing constants
MULTICAST_INTERVAL *= 10;
TCP_FALLBACK_DELAY *= 10;
TCP_INTERVAL *= 10;
UDP_FALLBACK_DELAY *= 10;
UDP_INTERVAL *= 10;
ConnectionSettings.BOOTSTRAP_DELAY.setValue(
ConnectionSettings.BOOTSTRAP_DELAY.getValue() * 10);
}
public void testMulticastTriedFirst() throws Exception {
context.checking(new Expectations() {{
// The listener needs hosts
one(listener).needsHosts();
will(returnValue(true));
// The bootstrapper should create and send a multicast ping
one(pingRequestFactory).createMulticastPing();
will(returnValue(pingRequest));
one(multicastService).send(pingRequest);
}});
bootstrapper.run();
context.assertIsSatisfied();
}
public void testUDPTriedFirstIfMulticastDisabled() throws Exception {
ConnectionSettings.DO_NOT_MULTICAST_BOOTSTRAP.setValue(true);
context.checking(new Expectations() {{
// The listener needs hosts
one(listener).needsHosts();
will(returnValue(true));
// Multicast is disabled - the bootstrapper should try UDP
one(udpHostCache).fetchHosts();
will(returnValue(true));
}});
bootstrapper.run();
context.assertIsSatisfied();
}
public void testUDPFallbackDelay() throws Exception {
context.checking(new Expectations() {{
// First call should use multicast
one(listener).needsHosts();
will(returnValue(true));
one(pingRequestFactory).createMulticastPing();
will(returnValue(pingRequest));
one(multicastService).send(pingRequest);
// Second call shouldn't use anything (too soon for UDP)
one(listener).needsHosts();
will(returnValue(true));
// Third call should use UDP
one(listener).needsHosts();
will(returnValue(true));
one(udpHostCache).fetchHosts();
will(returnValue(true));
}});
bootstrapper.run(); // Multicast
Thread.sleep(UDP_FALLBACK_DELAY - 10);
bootstrapper.run(); // Too soon for UDP
Thread.sleep(20);
bootstrapper.run(); // UDP
context.assertIsSatisfied();
}
public void testUDPTriedTwiceBeforeTCP() throws Exception {
// Sanity check: second UDP attempt comes before first TCP attempt
assertGreaterThan(UDP_INTERVAL, TCP_FALLBACK_DELAY);
// Sanity check: second UDP attempt comes before second multicast attempt
assertGreaterThan(UDP_INTERVAL, MULTICAST_INTERVAL - UDP_FALLBACK_DELAY);
context.checking(new Expectations() {{
// First call should use multicast
one(listener).needsHosts();
will(returnValue(true));
one(pingRequestFactory).createMulticastPing();
will(returnValue(pingRequest));
one(multicastService).send(pingRequest);
// Second call should use UDP
one(listener).needsHosts();
will(returnValue(true));
one(udpHostCache).fetchHosts();
will(returnValue(true));
// Third call should use UDP again
one(listener).needsHosts();
will(returnValue(true));
one(udpHostCache).fetchHosts();
will(returnValue(true));
// Fourth call should use TCP
one(listener).needsHosts();
will(returnValue(true));
one(tcpBootstrap).fetchHosts(listener);
will(returnValue(true));
}});
bootstrapper.run(); // Multicast
Thread.sleep(UDP_FALLBACK_DELAY + 10);
bootstrapper.run(); // UDP
Thread.sleep(UDP_INTERVAL + 10);
bootstrapper.run(); // UDP again
Thread.sleep(TCP_FALLBACK_DELAY - UDP_INTERVAL);
bootstrapper.run(); // TCP
context.assertIsSatisfied();
}
public void testBootstrapDelay() throws Exception {
context.checking(new Expectations() {{
// The listener has hosts but we're not connected yet
one(listener).needsHosts();
will(returnValue(false));
one(connectionServices).isConnected();
will(returnValue(false));
// Still not connected but it's too soon to bootstrap
one(listener).needsHosts();
will(returnValue(false));
one(connectionServices).isConnected();
will(returnValue(false));
// Give up on the listener's hosts and bootstrap
one(listener).needsHosts();
will(returnValue(false));
one(connectionServices).isConnected();
will(returnValue(false));
one(pingRequestFactory).createMulticastPing();
will(returnValue(pingRequest));
one(multicastService).send(pingRequest);
}});
bootstrapper.run(); // Too soon to bootstrap
Thread.sleep(ConnectionSettings.BOOTSTRAP_DELAY.getValue() - 10);
bootstrapper.run(); // Still too soon to bootstrap
Thread.sleep(20);
bootstrapper.run(); // Bootstrap
context.assertIsSatisfied();
}
public void testDoesNotBootstrapWhenConnected() throws Exception {
context.checking(new Expectations() {{
one(listener).needsHosts();
will(returnValue(false));
one(connectionServices).isConnected();
will(returnValue(true));
}});
bootstrapper.run();
context.assertIsSatisfied();
}
}