package com.limegroup.gnutella; import java.io.IOException; import java.lang.reflect.Method; import java.util.Properties; import junit.framework.Test; import com.limegroup.gnutella.connection.OutputRunner; import com.limegroup.gnutella.handshaking.HandshakeResponse; import com.limegroup.gnutella.messages.Message; import com.limegroup.gnutella.settings.ConnectionSettings; import com.limegroup.gnutella.settings.UltrapeerSettings; import com.limegroup.gnutella.stubs.ActivityCallbackStub; import com.limegroup.gnutella.util.BaseTestCase; import com.limegroup.gnutella.util.PrivilegedAccessor; /** * PARTIAL unit tests for ConnectionManager. Makes sure HostCatcher is notified * of right events. */ public class ConnectionManagerTest extends BaseTestCase { private static TestHostCatcher CATCHER; private static RouterService ROUTER_SERVICE; public ConnectionManagerTest(String name) { super(name); } public static Test suite() { return buildTestSuite(ConnectionManagerTest.class); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static void globalSetUp() throws Exception { ROUTER_SERVICE = new RouterService(new ActivityCallbackStub()); CATCHER = new TestHostCatcher(); setSettings(); launchAllBackends(); PrivilegedAccessor.setValue(ROUTER_SERVICE,"catcher",CATCHER); PrivilegedAccessor.setValue(RouterService.getConnectionManager(), "_catcher",CATCHER); ROUTER_SERVICE.start(); RouterService.clearHostCatcher(); } public void setUp() throws Exception { setSettings(); // Currently, there are no default EVIL_HOSTS useragents. to test this, we need // to pick on someone, so it will be Morpheus =) String [] agents = {"morpheus"}; ConnectionSettings.EVIL_HOSTS.setValue( agents ); } private static void setSettings() throws Exception { ConnectionSettings.PORT.setValue(6346); ConnectionSettings.CONNECT_ON_STARTUP.setValue(false); ConnectionSettings.LOCAL_IS_PRIVATE.setValue(false); ConnectionSettings.EVER_ACCEPTED_INCOMING.setValue(true); ConnectionSettings.USE_GWEBCACHE.setValue(false); UltrapeerSettings.FORCE_ULTRAPEER_MODE.setValue(true); UltrapeerSettings.EVER_ULTRAPEER_CAPABLE.setValue(true); ConnectionSettings.PREFERENCING_ACTIVE.setValue(false); UltrapeerSettings.NEED_MIN_CONNECT_TIME.setValue(true); } public void tearDown() { //Ensure no more threads. RouterService.disconnect(); RouterService.clearHostCatcher(); CATCHER.connectSuccess = 0; CATCHER.connectFailures = 0; CATCHER.endpoint = null; sleep(); } /** * Tests the method for checking whether or not connections should be * allowed. * * @throws Exception if an error occurs */ // public void testAllowConnection() throws Exception { // NOTA BENE: you may have to turn on ConnectionSettings.PREFERENCING_ACTIVE.setValue(true); // which is deactivated in this.setSettings() // } /** * Tests the method for allowing ultrapeer 2 ultrapeer connections. * * @throws Exception if an error occurs */ public void testAllowUltrapeer2UltrapeerConnection() throws Exception { Method m = PrivilegedAccessor.getMethod(ConnectionManager.class, "allowUltrapeer2UltrapeerConnection", new Class[] {HandshakeResponse.class}); HandshakeResponse hr = createTestResponse("Morpheus 3.3"); Object[] params = new Object[] {hr}; boolean allow = ((Boolean)m.invoke(ConnectionManager.class, params)).booleanValue(); assertFalse("connection should not have been allowed", allow); hr = createTestResponse("Bearshare 3.3"); params[0] = hr; allow = ((Boolean)m.invoke(ConnectionManager.class, params)).booleanValue(); assertTrue("connection should have been allowed", allow); hr = createTestResponse("LimeWire 3.3"); params[0] = hr; allow = ((Boolean)m.invoke(ConnectionManager.class, params)).booleanValue(); assertTrue("connection should have been allowed", allow); hr = createTestResponse("Shareaza 3.3"); params[0] = hr; allow = ((Boolean)m.invoke(ConnectionManager.class, params)).booleanValue(); assertTrue("connection should have been allowed", allow); } /** * Tests the method for allowing ultrapeer 2 leaf connections. * * @throws Exception if an error occurs */ public void testAllowUltrapeer2LeafConnection() throws Exception { Method m = PrivilegedAccessor.getMethod(ConnectionManager.class, "allowUltrapeer2LeafConnection", new Class[] {HandshakeResponse.class}); HandshakeResponse hr = createTestResponse("Morpheus 3.3"); Object[] params = new Object[] {hr}; boolean allow = ((Boolean)m.invoke(ConnectionManager.class, params)).booleanValue(); assertFalse("connection should not have been allowed", allow); hr = createTestResponse("Bearshare 3.3"); params[0] = hr; allow = ((Boolean)m.invoke(ConnectionManager.class, params)).booleanValue(); assertTrue("connection should have been allowed", allow); hr = createTestResponse("LimeWire 3.3"); params[0] = hr; allow = ((Boolean)m.invoke(ConnectionManager.class, params)).booleanValue(); assertTrue("connection should have been allowed", allow); hr = createTestResponse("Shareaza 3.3"); params[0] = hr; allow = ((Boolean)m.invoke(ConnectionManager.class, params)).booleanValue(); assertTrue("connection should have been allowed", allow); } /** * Utility method for creating a set of headers with the specified user * agent value. * * @param userAgent the User-Agent to include in the headers * @return a new <tt>HandshakeResponse</tt> with the specified user agent * @throws IOException if an error occurs */ private static HandshakeResponse createTestResponse(String userAgent) throws IOException { Properties headers = new Properties(); headers.put("User-Agent", userAgent); return HandshakeResponse.createResponse(headers); } public void testSupernodeStatus() throws Exception { UltrapeerSettings.FORCE_ULTRAPEER_MODE.setValue(false); UltrapeerSettings.NEED_MIN_CONNECT_TIME.setValue(true); ConnectionManager mgr = RouterService.getConnectionManager(); // test preconditions assertTrue("should not start as supernode", !mgr.isSupernode()); assertTrue("should not be a shielded leaf", !mgr.isShieldedLeaf()); UltrapeerSettings.MIN_CONNECT_TIME.setValue(0); setConnectTime(); assertTrue("should start as supernode", mgr.isSupernode()); assertTrue("should not be leaf", !mgr.isShieldedLeaf()); // construct peers // u ==> i should be ultrapeer // l ==> i should be leaf ManagedConnection u1, l1, l2; u1 = new SupernodeClient(true); l1 = new ClientSupernode(true); l2 = new ClientSupernode(true); // add a supernode => client connection initializeStart(u1); assertTrue("should still be supernode", mgr.isSupernode()); assertTrue("should still not be leaf", !mgr.isShieldedLeaf()); initializeDone(u1); assertTrue("should still be supernode", mgr.isSupernode()); assertTrue("should still not be leaf", !mgr.isShieldedLeaf()); mgr.remove(u1); assertTrue("should still be supernode", mgr.isSupernode()); assertTrue("should still not be leaf", !mgr.isShieldedLeaf()); // add a leaf -> supernode connection initializeStart(l1); assertTrue("should still be supernode", mgr.isSupernode()); assertTrue("should still not be leaf", !mgr.isShieldedLeaf()); initializeDone(l1); assertTrue("should not be supernode", !mgr.isSupernode()); assertTrue("should be leaf", mgr.isShieldedLeaf()); mgr.remove(l1); assertTrue("should be supernode", mgr.isSupernode()); assertTrue("should not be leaf", !mgr.isShieldedLeaf()); // test a strange condition // (two leaves start, second finishes then removes, // third removes then finishes) initializeStart(l1); initializeStart(l2); initializeDone(l2); assertTrue("should not be supernode", !mgr.isSupernode()); assertTrue("should be leaf", mgr.isShieldedLeaf()); mgr.remove(l2); assertTrue("should be supernode", mgr.isSupernode()); assertTrue("should not be leaf", !mgr.isShieldedLeaf()); mgr.remove(l1); assertTrue("should be supernode", mgr.isSupernode()); assertTrue("should not be leaf", !mgr.isShieldedLeaf()); initializeDone(l1); assertTrue("should be supernode", mgr.isSupernode()); assertTrue("should not be leaf", !mgr.isShieldedLeaf()); } /** * Tests the various connection-counting methods */ public void testGetNumberOfConnections() throws Exception { ManagedConnection[] limeLeaves = new ManagedConnection[30]; ManagedConnection[] nonLimeLeaves = new ManagedConnection[30]; ManagedConnection[] limePeers = new ManagedConnection[32]; ManagedConnection[] nonLimePeers = new ManagedConnection[32]; for(int i = 0; i < limeLeaves.length; i++) limeLeaves[i] = new SupernodeClient(true); for(int i = 0; i < nonLimeLeaves.length; i++) nonLimeLeaves[i] = new SupernodeClient(false); for(int i = 0; i < limePeers.length; i++) limePeers[i] = new SupernodeSupernode(true); for(int i = 0; i < nonLimePeers.length; i++) nonLimePeers[i] = new SupernodeSupernode(false); UltrapeerSettings.FORCE_ULTRAPEER_MODE.setValue(true); ConnectionManager mgr = RouterService.getConnectionManager(); setConnectTime(); // test preconditions assertTrue("should start as supernode", mgr.isSupernode()); assertTrue("should not be leaf", !mgr.isShieldedLeaf()); pretendConnected(); assertEquals(32, mgr.getNumFreeNonLeafSlots()); assertEquals(27, mgr.getNumFreeLimeWireNonLeafSlots()); assertEquals(30, mgr.getNumFreeLeafSlots()); assertEquals(28, mgr.getNumFreeLimeWireLeafSlots()); // Add 10 limewire leaves and 5 limewire peers. for(int i = 0; i < 10; i++) { initializeStart(limeLeaves[i]); initializeDone(limeLeaves[i]); } for(int i = 0; i < 5; i++) { initializeStart(limePeers[i]); initializeDone(limePeers[i]); } // Are now 10 lime leaves & 5 lime peers. // Equaling: 10 leaves & 5 peers. assertEquals(20, mgr.getNumFreeLeafSlots()); assertEquals(18, mgr.getNumFreeLimeWireLeafSlots()); assertEquals(27, mgr.getNumFreeNonLeafSlots()); assertEquals(24, mgr.getNumFreeLimeWireNonLeafSlots()); // Add 1 non lime leaf and 2 non limewire peers. for(int i = 0; i < 1; i++) { initializeStart(nonLimeLeaves[i]); initializeDone(nonLimeLeaves[i]); } for(int i = 0; i < 2; i++) { initializeStart(nonLimePeers[i]); initializeDone(nonLimePeers[i]); } // Are now 10 lime leaves, 1 non lime leaf, 5 lime peers, 2 non lime peers // Equaling: 11 leaves & 7 peers assertEquals(19, mgr.getNumFreeLeafSlots()); assertEquals(18, mgr.getNumFreeLimeWireLeafSlots()); assertEquals(25, mgr.getNumFreeNonLeafSlots()); assertEquals(24, mgr.getNumFreeLimeWireNonLeafSlots()); // Add a bunch of non lime peers & leaves. for(int i = 1; i < 15; i++) { initializeStart(nonLimeLeaves[i]); initializeDone(nonLimeLeaves[i]); } for(int i = 2; i < 15; i++) { initializeStart(nonLimePeers[i]); initializeDone(nonLimePeers[i]); } // There are now 15 non lime leaves & non lime peers connected, // 10 lime leaves, and 5 lime peers. // Equaling: 25 leaves and 20 peers. assertEquals(5, mgr.getNumFreeLeafSlots()); assertEquals(5, mgr.getNumFreeLimeWireLeafSlots()); assertEquals(12, mgr.getNumFreeNonLeafSlots()); assertEquals(12, mgr.getNumFreeLimeWireNonLeafSlots()); // Add 5 lime leaves and 12 lime peers for(int i = 10; i < 15; i++) { initializeStart(limeLeaves[i]); initializeDone(limeLeaves[i]); } for(int i = 5; i < 17; i++) { initializeStart(limePeers[i]); initializeDone(limePeers[i]); } // There are now 15 non lime leaves & non lime peers, // 15 lime leaves, and 17 lime peers. // Equaling: 30 leaves and 32 peers. assertEquals(0, mgr.getNumFreeLeafSlots()); assertEquals(0, mgr.getNumFreeLimeWireLeafSlots()); assertEquals(0, mgr.getNumFreeNonLeafSlots()); assertEquals(0, mgr.getNumFreeLimeWireNonLeafSlots()); // Now kill all but 2 of the non lime leaves // and all but 3 of non lime peers. for(int i = 14; i >= 2; i--) mgr.remove(nonLimeLeaves[i]); for(int i = 14; i >= 3; i--) mgr.remove(nonLimePeers[i]); // There are now 2 non lime leaves and 3 non lime peers, // and 15 lime leaves and 17 lime peers. // Equaling: 17 leaves and 20 peers assertEquals(13, mgr.getNumFreeLeafSlots()); assertEquals(13, mgr.getNumFreeLimeWireLeafSlots()); assertEquals(12, mgr.getNumFreeNonLeafSlots()); assertEquals(12, mgr.getNumFreeLimeWireNonLeafSlots()); // Now add 13 lime leaves and 12 lime peers. for(int i = 15; i < 28; i++) { initializeStart(limeLeaves[i]); initializeDone(limeLeaves[i]); } for(int i = 17; i < 29; i++) { initializeStart(limePeers[i]); initializeDone(limePeers[i]); } // There are now 2 non lime leaves and 3 non lime peers, // and 28 lime leaves and 29 lime peers // Equaling: 30 leaves and 32 peers assertEquals(0, mgr.getNumFreeLeafSlots()); assertEquals(0, mgr.getNumFreeLimeWireLeafSlots()); assertEquals(0, mgr.getNumFreeNonLeafSlots()); assertEquals(0, mgr.getNumFreeLimeWireNonLeafSlots()); // Now kill off the rest of the non lime peers and leaves. for(int i = 1; i >= 0; i--) mgr.remove(nonLimeLeaves[i]); for(int i = 2; i >= 0; i--) mgr.remove(nonLimePeers[i]); // There are now no non lime leaves and no non lime peers, // and 28 lime leaves and 29 lime peers // Equaling: 28 leaves and 29 peers assertEquals(2, mgr.getNumFreeLeafSlots()); assertEquals(0, mgr.getNumFreeLimeWireLeafSlots()); assertEquals(3, mgr.getNumFreeNonLeafSlots()); assertEquals(0, mgr.getNumFreeLimeWireNonLeafSlots()); } /** * Tests to make sure that a connection does not succeed with an * unreachable host. */ public void testUnreachableHost() { CATCHER.endpoint = new ExtendedEndpoint("1.2.3.4", 5000); RouterService.connect(); sleep(15000); assertEquals("unexpected successful connect", 0, CATCHER.connectSuccess); assertGreaterThan("should have received failures", 0, CATCHER.connectFailures); } /** * Test to make sure tests does not succeed with a host reporting * the wrong protocol. */ public void testWrongProtocolHost() { CATCHER.endpoint = new ExtendedEndpoint("www.yahoo.com", 80); RouterService.connect(); sleep(); assertEquals("unexpected successful connect", 0, CATCHER.connectSuccess); assertGreaterThan("should have received failures", 0, CATCHER.connectFailures); //assertEquals("should have received failure", 1, CATCHER.connectFailures); } /** * Test to make sure that a good host is successfully connected to. */ public void testGoodHost() { CATCHER.endpoint = new ExtendedEndpoint("localhost", Backend.BACKEND_PORT); RouterService.connect(); sleep(); assertEquals("connect should have succeeded", 1, CATCHER.connectSuccess); assertEquals("connect should have failed", 0, CATCHER.connectFailures); } /** * Tests to make sure that a host is still added to the host * catcher as a connection that was made (at least temporarily) even * if the server sent a 503. */ public void testRejectHost() { CATCHER.endpoint = new ExtendedEndpoint("localhost", Backend.REJECT_PORT); RouterService.connect(); sleep(); assertEquals("connect should have succeeded", 1, CATCHER.connectSuccess); assertEquals("connect should have failed", 0, CATCHER.connectFailures); } private void sleep() { sleep(5000); } private void sleep(int milliseconds) { try { Thread.sleep(milliseconds); } catch (InterruptedException e) { } } private void setConnectTime() throws Exception { PrivilegedAccessor.setValue(RouterService.getConnectionManager(), "_connectTime", new Integer(0)); } private void initializeStart(ManagedConnection c) throws Exception { // Need to setup the _outputRunner member of c as well... PrivilegedAccessor.setValue(c, "_outputRunner", new NullOutputRunner() ); PrivilegedAccessor.invokeMethod( RouterService.getConnectionManager(), "connectionInitializingIncoming", new Object[] { c }, new Class[] { ManagedConnection.class} ); } private void initializeDone(ManagedConnection c) throws Exception { PrivilegedAccessor.invokeMethod( RouterService.getConnectionManager(), "connectionInitialized", new Object[] { c }, new Class[] { ManagedConnection.class} ); } /** * Test host catcher that allows us to return endpoints that we * specify when our test framework requests endpoints to connect * to. */ private static class TestHostCatcher extends HostCatcher { private volatile ExtendedEndpoint endpoint; private volatile int connectSuccess=0; private volatile int connectFailures=0; TestHostCatcher() { super(); } protected ExtendedEndpoint getAnEndpointInternal() { if(endpoint == null) return null; else { ExtendedEndpoint ret = endpoint; endpoint = null; return ret; } } public synchronized void doneWithConnect(Endpoint e, boolean success) { if (success) connectSuccess++; else connectFailures++; } // Overridden because initialize() was previously overridden, but that missed // setting up some required members. Now, the code which was intended to be // skipped was moved into this function (on the base class) public void scheduleServices() { } } private static class TestManagedConnection extends ManagedConnection { private boolean isOutgoing; private int sent; private int received; private static int lastHost = 0; public TestManagedConnection(boolean isOutgoing, int sent, int received) { super("1.2.3." + ++lastHost, 6346); this.isOutgoing=isOutgoing; this.sent=sent; this.received=received; } public boolean isOutgoing() { return isOutgoing; } public int getNumMessagesSent() { return sent; } public int getNumMessagesReceived() { return received; } protected void startOutputRunner() { // do nothing } } private static class ClientSupernode extends TestManagedConnection { final boolean isLime; ClientSupernode(boolean lime) { super(false, 0, 0); isLime = lime; } public boolean isClientSupernodeConnection() { return true; } public boolean isSupernodeClientConnection() { return false; } public boolean isLimeWire() { return isLime; } } private static class SupernodeClient extends TestManagedConnection { final boolean isLime; SupernodeClient(boolean lime) { super(false, 0, 0); isLime = lime; } public boolean isClientSupernodeConnection() { return false; } public boolean isSupernodeClientConnection() { return true; } public boolean isLimeWire() { return isLime; } } private static class SupernodeSupernode extends TestManagedConnection { final boolean isLime; SupernodeSupernode(boolean lime) { super(false, 0, 0); isLime = lime; } public boolean isSupernodeSupernodeConnection() { return false; } public boolean isClientSupernodeConnection() { return false; } public boolean isSupernodeClientConnection() { return false; } public boolean isLimeWire() { return isLime; } } private void pretendConnected() throws Exception { ConnectionManager mgr = RouterService.getConnectionManager(); PrivilegedAccessor.setValue(mgr, "_disconnectTime", new Integer(0)); PrivilegedAccessor.invokeMethod(mgr, "setPreferredConnections", null); } private class NullOutputRunner implements OutputRunner { // Overridden methods do nothing public void send(Message m) {} public void shutdown() {} } }