From 500a90ac4ab174e420c04a2a502630c2e8323a20 Mon Sep 17 00:00:00 2001 From: Devin Bileck <603793+devinbileck@users.noreply.github.com> Date: Sat, 9 Nov 2019 23:44:11 -0800 Subject: [PATCH] Add PeerManagerTest The old PeerManagerTest was located under network/p2p/routing, which is no longer the correct location. Additionally, it was outdated so I just removed it and added a new file under network/p2p/peers containing tests for checkMaxConnections. --- .../bisq/network/p2p/PeerManagerTest.java | 187 +++++++ .../network/p2p/routing/PeerManagerTest.java | 486 ------------------ 2 files changed, 187 insertions(+), 486 deletions(-) create mode 100644 p2p/src/test/java/bisq/network/p2p/PeerManagerTest.java delete mode 100644 p2p/src/test/java/bisq/network/p2p/routing/PeerManagerTest.java diff --git a/p2p/src/test/java/bisq/network/p2p/PeerManagerTest.java b/p2p/src/test/java/bisq/network/p2p/PeerManagerTest.java new file mode 100644 index 00000000000..0e0eb2c298a --- /dev/null +++ b/p2p/src/test/java/bisq/network/p2p/PeerManagerTest.java @@ -0,0 +1,187 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.network.p2p.peers; + +import bisq.network.p2p.network.CloseConnectionReason; +import bisq.network.p2p.network.Connection; +import bisq.network.p2p.network.InboundConnection; + +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.isA; +import static org.mockito.Mockito.*; + +public class PeerManagerTest { + private MockNode node; + private int maxConnectionsPeer; + private int maxConnectionsNonDirect; + + @Before + public void Setup() { + node = new MockNode(2); + maxConnectionsPeer = Math.max(4, (int) Math.round(node.getMaxConnections() * 1.3)); + maxConnectionsNonDirect = Math.max(8, (int) Math.round(node.getMaxConnections() * 1.7)); + } + + @Test + public void testCheckMaxConnectionsNotExceeded() { + for (int i = 0; i < 2; i++) { + node.addInboundConnection(Connection.PeerType.PEER); + } + assertEquals(2, node.getNetworkNode().getAllConnections().size()); + + assertFalse(node.getPeerManager().checkMaxConnections()); + + node.getNetworkNode().getAllConnections().forEach(connection -> { + verify(connection, never()).shutDown(eq(CloseConnectionReason.TOO_MANY_CONNECTIONS_OPEN), isA(Runnable.class)); + }); + } + + @Test + public void testCheckMaxConnectionsExceededWithInboundPeers() throws InterruptedException { + for (int i = 0; i < 3; i++) { + node.addInboundConnection(Connection.PeerType.PEER); + } + assertEquals(3, node.getNetworkNode().getAllConnections().size()); + List inboundSortedPeerConnections = node.getNetworkNode().getAllConnections().stream() + .filter(e -> e instanceof InboundConnection) + .filter(e -> e.getPeerType() == Connection.PeerType.PEER) + .sorted(Comparator.comparingLong(o -> o.getStatistic().getLastActivityTimestamp())) + .collect(Collectors.toList()); + Connection oldestConnection = inboundSortedPeerConnections.remove(0); + + assertTrue(node.getPeerManager().checkMaxConnections()); + // Need to wait because the shutDownCompleteHandler calls + // checkMaxConnections on the user thread after a delay + Thread.sleep(500); + + verify(oldestConnection, times(1)).shutDown( + eq(CloseConnectionReason.TOO_MANY_CONNECTIONS_OPEN), + isA(Runnable.class)); + inboundSortedPeerConnections.forEach(connection -> { + verify(connection, never()).shutDown( + eq(CloseConnectionReason.TOO_MANY_CONNECTIONS_OPEN), + isA(Runnable.class)); + }); + } + + @Test + public void testCheckMaxConnectionsPeerLimitNotExceeded() { + for (int i = 0; i < maxConnectionsPeer; i++) { + node.addOutboundConnection(Connection.PeerType.PEER); + } + assertEquals(maxConnectionsPeer, node.getNetworkNode().getAllConnections().size()); + + assertFalse(node.getPeerManager().checkMaxConnections()); + + node.getNetworkNode().getAllConnections().forEach(connection -> { + verify(connection, never()).shutDown(eq(CloseConnectionReason.TOO_MANY_CONNECTIONS_OPEN), isA(Runnable.class)); + }); + } + + @Test + public void testCheckMaxConnectionsPeerLimitExceeded() throws InterruptedException { + for (int i = 0; i < maxConnectionsPeer + 1; i++) { + node.addOutboundConnection(Connection.PeerType.PEER); + } + assertEquals(maxConnectionsPeer + 1, node.getNetworkNode().getAllConnections().size()); + List sortedPeerConnections = node.getNetworkNode().getAllConnections().stream() + .filter(e -> e.getPeerType() == Connection.PeerType.PEER) + .sorted(Comparator.comparingLong(o -> o.getStatistic().getLastActivityTimestamp())) + .collect(Collectors.toList()); + Connection oldestConnection = sortedPeerConnections.remove(0); + + assertTrue(node.getPeerManager().checkMaxConnections()); + // Need to wait because the shutDownCompleteHandler calls + // checkMaxConnections on the user thread after a delay + Thread.sleep(500); + + verify(oldestConnection, times(1)).shutDown( + eq(CloseConnectionReason.TOO_MANY_CONNECTIONS_OPEN), + isA(Runnable.class)); + sortedPeerConnections.forEach(connection -> { + verify(connection, never()).shutDown( + eq(CloseConnectionReason.TOO_MANY_CONNECTIONS_OPEN), + isA(Runnable.class)); + }); + } + + @Test + public void testCheckMaxConnectionsNonDirectLimitNotExceeded() { + for (int i = 0; i < maxConnectionsNonDirect; i++) { + node.addOutboundConnection(Connection.PeerType.SEED_NODE); + } + assertEquals(maxConnectionsNonDirect, node.getNetworkNode().getAllConnections().size()); + + assertFalse(node.getPeerManager().checkMaxConnections()); + + node.getNetworkNode().getAllConnections().forEach(connection -> { + verify(connection, never()).shutDown(eq(CloseConnectionReason.TOO_MANY_CONNECTIONS_OPEN), isA(Runnable.class)); + }); + } + + @Test + public void testCheckMaxConnectionsNonDirectLimitExceeded() throws InterruptedException { + for (int i = 0; i < maxConnectionsNonDirect + 1; i++) { + node.addOutboundConnection(Connection.PeerType.PEER); + } + assertEquals(maxConnectionsNonDirect + 1, node.getNetworkNode().getAllConnections().size()); + List sortedPeerConnections = node.getNetworkNode().getAllConnections().stream() + .filter(e -> e.getPeerType() != Connection.PeerType.DIRECT_MSG_PEER && + e.getPeerType() != Connection.PeerType.INITIAL_DATA_REQUEST) + .sorted(Comparator.comparingLong(o -> o.getStatistic().getLastActivityTimestamp())) + .collect(Collectors.toList()); + Connection oldestConnection = sortedPeerConnections.remove(0); + + assertTrue(node.getPeerManager().checkMaxConnections()); + // Need to wait because the shutDownCompleteHandler calls + // checkMaxConnections on the user thread after a delay + Thread.sleep(500); + + verify(oldestConnection, times(1)).shutDown( + eq(CloseConnectionReason.TOO_MANY_CONNECTIONS_OPEN), + isA(Runnable.class)); + sortedPeerConnections.forEach(connection -> { + verify(connection, never()).shutDown( + eq(CloseConnectionReason.TOO_MANY_CONNECTIONS_OPEN), + isA(Runnable.class)); + }); + } + + @Test + public void testCheckMaxConnectionsExceededWithOutboundSeeds() { + for (int i = 0; i < 3; i++) { + node.addOutboundConnection(Connection.PeerType.SEED_NODE); + } + assertEquals(3, node.getNetworkNode().getAllConnections().size()); + + assertFalse(node.getPeerManager().checkMaxConnections()); + + node.getNetworkNode().getAllConnections().forEach(connection -> { + verify(connection, never()).shutDown(eq(CloseConnectionReason.TOO_MANY_CONNECTIONS_OPEN), isA(Runnable.class)); + }); + } +} diff --git a/p2p/src/test/java/bisq/network/p2p/routing/PeerManagerTest.java b/p2p/src/test/java/bisq/network/p2p/routing/PeerManagerTest.java deleted file mode 100644 index c9b14584d65..00000000000 --- a/p2p/src/test/java/bisq/network/p2p/routing/PeerManagerTest.java +++ /dev/null @@ -1,486 +0,0 @@ -/* - * This file is part of Bisq. - * - * Bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Bisq. If not, see . - */ - -package bisq.network.p2p.routing; - -import bisq.network.p2p.DummySeedNode; -import bisq.network.p2p.NodeAddress; -import bisq.network.p2p.P2PService; -import bisq.network.p2p.P2PServiceListener; -import bisq.network.p2p.network.LocalhostNetworkNode; - -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.CountDownLatch; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.junit.After; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; - -// TorNode created. Took 6 sec. -// Hidden service created. Took 40-50 sec. -// Connection establishment takes about 4 sec. - -// need to define seed node addresses first before using tor version -//TODO P2P network tests are outdated -@SuppressWarnings({"UnusedAssignment", "EmptyMethod"}) -@Ignore -public class PeerManagerTest { - private static final Logger log = LoggerFactory.getLogger(PeerManagerTest.class); - private static final int MAX_CONNECTIONS = 100; - - final boolean useLocalhostForP2P = true; - private CountDownLatch latch; - private Set seedNodes; - private int sleepTime; - private DummySeedNode seedNode1, seedNode2, seedNode3; - - @Before - public void setup() throws InterruptedException { - LocalhostNetworkNode.setSimulateTorDelayTorNode(50); - LocalhostNetworkNode.setSimulateTorDelayHiddenService(8); - - seedNodes = new HashSet<>(); - //noinspection ConstantConditions - if (useLocalhostForP2P) { - //seedNodes.add(new NodeAddress("localhost:8001")); - // seedNodes.add(new NodeAddress("localhost:8002")); - seedNodes.add(new NodeAddress("localhost:8003")); - sleepTime = 100; - - } else { - seedNodes.add(new NodeAddress("3omjuxn7z73pxoee.onion:8001")); - seedNodes.add(new NodeAddress("j24fxqyghjetgpdx.onion:8002")); - seedNodes.add(new NodeAddress("45367tl6unwec6kw.onion:8003")); - sleepTime = 1000; - } - } - - @After - public void tearDown() throws InterruptedException { - Thread.sleep(sleepTime); - - if (seedNode1 != null) { - CountDownLatch shutDownLatch = new CountDownLatch(1); - seedNode1.shutDown(shutDownLatch::countDown); - shutDownLatch.await(); - } - if (seedNode2 != null) { - CountDownLatch shutDownLatch = new CountDownLatch(1); - seedNode2.shutDown(shutDownLatch::countDown); - shutDownLatch.await(); - } - if (seedNode3 != null) { - CountDownLatch shutDownLatch = new CountDownLatch(1); - seedNode3.shutDown(shutDownLatch::countDown); - shutDownLatch.await(); - } - } - - // @Test - public void testSingleSeedNode() throws InterruptedException { - LocalhostNetworkNode.setSimulateTorDelayTorNode(0); - LocalhostNetworkNode.setSimulateTorDelayHiddenService(0); - seedNodes = new HashSet<>(); - NodeAddress nodeAddress = new NodeAddress("localhost:8001"); - seedNodes.add(nodeAddress); - seedNode1 = new DummySeedNode("test_dummy_dir"); - latch = new CountDownLatch(2); - seedNode1.createAndStartP2PService(nodeAddress, MAX_CONNECTIONS, useLocalhostForP2P, 2, true, - seedNodes, new P2PServiceListener() { - @Override - public void onDataReceived() { - latch.countDown(); - } - - @Override - public void onTorNodeReady() { - } - - @Override - public void onNoSeedNodeAvailable() { - } - - @Override - public void onNoPeersAvailable() { - } - - @Override - public void onUpdatedDataReceived() { - } - - @Override - public void onHiddenServicePublished() { - latch.countDown(); - } - - @Override - public void onSetupFailed(Throwable throwable) { - - } - - @Override - public void onRequestCustomBridges() { - - } - }); - P2PService p2PService1 = seedNode1.getSeedNodeP2PService(); - latch.await(); - Thread.sleep(500); - //Assert.assertEquals(0, p2PService1.getPeerManager().getAuthenticatedAndReportedPeers().size()); - } - - @Test - public void test2SeedNodes() throws InterruptedException { - LocalhostNetworkNode.setSimulateTorDelayTorNode(0); - LocalhostNetworkNode.setSimulateTorDelayHiddenService(0); - seedNodes = new HashSet<>(); - NodeAddress nodeAddress1 = new NodeAddress("localhost:8001"); - seedNodes.add(nodeAddress1); - NodeAddress nodeAddress2 = new NodeAddress("localhost:8002"); - seedNodes.add(nodeAddress2); - - latch = new CountDownLatch(6); - - seedNode1 = new DummySeedNode("test_dummy_dir"); - seedNode1.createAndStartP2PService(nodeAddress1, MAX_CONNECTIONS, useLocalhostForP2P, 2, true, seedNodes, new P2PServiceListener() { - @Override - public void onDataReceived() { - latch.countDown(); - } - - @Override - public void onNoSeedNodeAvailable() { - } - - @Override - public void onTorNodeReady() { - } - - @Override - public void onNoPeersAvailable() { - } - - @Override - public void onUpdatedDataReceived() { - latch.countDown(); - } - - @Override - public void onHiddenServicePublished() { - latch.countDown(); - } - - @Override - public void onSetupFailed(Throwable throwable) { - } - - @Override - public void onRequestCustomBridges() { - - } - }); - P2PService p2PService1 = seedNode1.getSeedNodeP2PService(); - - Thread.sleep(500); - - seedNode2 = new DummySeedNode("test_dummy_dir"); - seedNode2.createAndStartP2PService(nodeAddress2, MAX_CONNECTIONS, useLocalhostForP2P, 2, true, seedNodes, new P2PServiceListener() { - @Override - public void onDataReceived() { - latch.countDown(); - } - - @Override - public void onNoSeedNodeAvailable() { - } - - @Override - public void onTorNodeReady() { - } - - @Override - public void onNoPeersAvailable() { - } - - @Override - public void onUpdatedDataReceived() { - latch.countDown(); - } - - @Override - public void onHiddenServicePublished() { - latch.countDown(); - } - - @Override - public void onSetupFailed(Throwable throwable) { - } - - @Override - public void onRequestCustomBridges() { - - } - }); - P2PService p2PService2 = seedNode2.getSeedNodeP2PService(); - latch.await(); - // Assert.assertEquals(1, p2PService1.getPeerManager().getAuthenticatedAndReportedPeers().size()); - // Assert.assertEquals(1, p2PService2.getPeerManager().getAuthenticatedAndReportedPeers().size()); - } - - // @Test - public void testAuthentication() throws InterruptedException { - log.debug("### start"); - LocalhostNetworkNode.setSimulateTorDelayTorNode(0); - LocalhostNetworkNode.setSimulateTorDelayHiddenService(0); - DummySeedNode seedNode1 = getAndStartSeedNode(8001); - log.debug("### seedNode1"); - Thread.sleep(100); - log.debug("### seedNode1 100"); - Thread.sleep(1000); - DummySeedNode seedNode2 = getAndStartSeedNode(8002); - - // authentication: - // node2 -> node1 RequestAuthenticationMessage - // node1: close connection - // node1 -> node2 ChallengeMessage on new connection - // node2: authentication to node1 done if nonce ok - // node2 -> node1 GetPeersMessage - // node1: authentication to node2 done if nonce ok - // node1 -> node2 PeersMessage - - // first authentication from seedNode2 to seedNode1, then from seedNode1 to seedNode2 - //TODO - /* CountDownLatch latch1 = new CountDownLatch(2); - AuthenticationListener routingListener1 = new AuthenticationListener() { - @Override - public void onConnectionAuthenticated(Connection connection) { - log.debug("onConnectionAuthenticated " + connection); - latch1.countDown(); - } - }; - seedNode1.getP2PService().getPeerGroup().addPeerListener(routingListener1); - - AuthenticationListener routingListener2 = new AuthenticationListener() { - @Override - public void onConnectionAuthenticated(Connection connection) { - log.debug("onConnectionAuthenticated " + connection); - latch1.countDown(); - } - }; - seedNode2.getP2PService().getPeerGroup().addPeerListener(routingListener2); - latch1.await(); - seedNode1.getP2PService().getPeerGroup().removePeerListener(routingListener1); - seedNode2.getP2PService().getPeerGroup().removePeerListener(routingListener2); - - // wait until Peers msg finished - Thread.sleep(sleepTime); - - // authentication: - // authentication from seedNode3 to seedNode1, then from seedNode1 to seedNode3 - // authentication from seedNode3 to seedNode2, then from seedNode2 to seedNode3 - SeedNode seedNode3 = getAndStartSeedNode(8003); - CountDownLatch latch2 = new CountDownLatch(3); - seedNode1.getP2PService().getPeerGroup().addPeerListener(new AuthenticationListener() { - @Override - public void onConnectionAuthenticated(Connection connection) { - log.debug("onConnectionAuthenticated " + connection); - latch2.countDown(); - } - }); - seedNode2.getP2PService().getPeerGroup().addPeerListener(new AuthenticationListener() { - @Override - public void onConnectionAuthenticated(Connection connection) { - log.debug("onConnectionAuthenticated " + connection); - latch2.countDown(); - } - }); - seedNode3.getP2PService().getPeerGroup().addPeerListener(new AuthenticationListener() { - @Override - public void onConnectionAuthenticated(Connection connection) { - log.debug("onConnectionAuthenticated " + connection); - latch2.countDown(); - } - }); - latch2.await(); - - // wait until Peers msg finished - Thread.sleep(sleepTime); - - - CountDownLatch shutDownLatch = new CountDownLatch(3); - seedNode1.shutDown(() -> shutDownLatch.countDown()); - seedNode2.shutDown(() -> shutDownLatch.countDown()); - seedNode3.shutDown(() -> shutDownLatch.countDown()); - shutDownLatch.await();*/ - } - - //@Test - public void testAuthenticationWithDisconnect() throws InterruptedException { - //TODO - /* LocalhostNetworkNode.setSimulateTorDelayTorNode(0); - LocalhostNetworkNode.setSimulateTorDelayHiddenService(0); - SeedNode seedNode1 = getAndStartSeedNode(8001); - SeedNode seedNode2 = getAndStartSeedNode(8002); - - // authentication: - // node2 -> node1 RequestAuthenticationMessage - // node1: close connection - // node1 -> node2 ChallengeMessage on new connection - // node2: authentication to node1 done if nonce ok - // node2 -> node1 GetPeersMessage - // node1: authentication to node2 done if nonce ok - // node1 -> node2 PeersMessage - - // first authentication from seedNode2 to seedNode1, then from seedNode1 to seedNode2 - CountDownLatch latch1 = new CountDownLatch(2); - AuthenticationListener routingListener1 = new AuthenticationListener() { - @Override - public void onConnectionAuthenticated(Connection connection) { - log.debug("onConnectionAuthenticated " + connection); - latch1.countDown(); - } - }; - seedNode1.getP2PService().getPeerGroup().addPeerListener(routingListener1); - - AuthenticationListener routingListener2 = new AuthenticationListener() { - @Override - public void onConnectionAuthenticated(Connection connection) { - log.debug("onConnectionAuthenticated " + connection); - latch1.countDown(); - } - }; - seedNode2.getP2PService().getPeerGroup().addPeerListener(routingListener2); - latch1.await(); - - // shut down node 2 - Thread.sleep(sleepTime); - seedNode1.getP2PService().getPeerGroup().removePeerListener(routingListener1); - seedNode2.getP2PService().getPeerGroup().removePeerListener(routingListener2); - CountDownLatch shutDownLatch1 = new CountDownLatch(1); - seedNode2.shutDown(() -> shutDownLatch1.countDown()); - shutDownLatch1.await(); - - // restart node 2 - seedNode2 = getAndStartSeedNode(8002); - CountDownLatch latch3 = new CountDownLatch(1); - routingListener2 = new AuthenticationListener() { - @Override - public void onConnectionAuthenticated(Connection connection) { - log.debug("onConnectionAuthenticated " + connection); - latch3.countDown(); - } - }; - seedNode2.getP2PService().getPeerGroup().addPeerListener(routingListener2); - latch3.await(); - - Thread.sleep(sleepTime); - - CountDownLatch shutDownLatch = new CountDownLatch(2); - seedNode1.shutDown(() -> shutDownLatch.countDown()); - seedNode2.shutDown(() -> shutDownLatch.countDown()); - shutDownLatch.await();*/ - } - - //@Test - public void testAuthenticationWithManyNodes() throws InterruptedException { - //TODO - /* int authentications = 0; - int length = 3; - SeedNode[] nodes = new SeedNode[length]; - for (int i = 0; i < length; i++) { - SeedNode node = getAndStartSeedNode(8001 + i); - nodes[i] = node; - - latch = new CountDownLatch(i * 2); - authentications += (i * 2); - node.getP2PService().getPeerGroup().addPeerListener(new AuthenticationListener() { - @Override - public void onConnectionAuthenticated(Connection connection) { - log.debug("onConnectionAuthenticated " + connection); - latch.countDown(); - } - }); - latch.await(); - Thread.sleep(sleepTime); - } - - log.debug("total authentications " + authentications); - Profiler.printSystemLoad(log); - // total authentications at 8 nodes = 56 - // total authentications at com nodes = 90, System load (no. threads/used memory (MB)): 170/20 - // total authentications at 20 nodes = 380, System load (no. threads/used memory (MB)): 525/46 - for (int i = 0; i < length; i++) { - nodes[i].getP2PService().getPeerGroup().printAuthenticatedPeers(); - nodes[i].getP2PService().getPeerGroup().printReportedPeers(); - } - - CountDownLatch shutDownLatch = new CountDownLatch(length); - for (int i = 0; i < length; i++) { - nodes[i].shutDown(() -> shutDownLatch.countDown()); - } - shutDownLatch.await();*/ - } - - private DummySeedNode getAndStartSeedNode(int port) throws InterruptedException { - DummySeedNode seedNode = new DummySeedNode("test_dummy_dir"); - - latch = new CountDownLatch(1); - seedNode.createAndStartP2PService(new NodeAddress("localhost", port), MAX_CONNECTIONS, useLocalhostForP2P, 2, true, seedNodes, new P2PServiceListener() { - @Override - public void onDataReceived() { - latch.countDown(); - } - - @Override - public void onNoSeedNodeAvailable() { - } - - @Override - public void onTorNodeReady() { - } - - @Override - public void onNoPeersAvailable() { - } - - @Override - public void onUpdatedDataReceived() { - } - - @Override - public void onHiddenServicePublished() { - } - - @Override - public void onSetupFailed(Throwable throwable) { - } - - @Override - public void onRequestCustomBridges() { - - } - }); - latch.await(); - Thread.sleep(sleepTime); - return seedNode; - } -}