diff --git a/src/main/java/io/bitsquare/app/ArgumentParser.java b/src/main/java/io/bitsquare/app/ArgumentParser.java index 39ca8f2743..c2a59f7943 100644 --- a/src/main/java/io/bitsquare/app/ArgumentParser.java +++ b/src/main/java/io/bitsquare/app/ArgumentParser.java @@ -17,46 +17,37 @@ package io.bitsquare.app; -import io.bitsquare.network.BootstrapNode; +import io.bitsquare.network.BootstrapNodes; +import io.bitsquare.network.Node; import net.sourceforge.argparse4j.ArgumentParsers; import net.sourceforge.argparse4j.inf.ArgumentParserException; import net.sourceforge.argparse4j.inf.Namespace; -/* -optional arguments: - -h, --help show this help message and exit - -d PEER_ID, --peerid PEER Seed peer ID (default: "digitalocean1.bitsquare.io") - -p PORT, --port PORT IP port to listen on. (default: 5000) - -i INTERFACE, --interface INTERFACE Network interface to listen on. - -n NAME, --name NAME Append name to application name. - */ public class ArgumentParser { public static final String PEER_ID_FLAG = "peerid"; public static final String PORT_FLAG = "port"; public static final String INTERFACE_HINT_FLAG = "interface"; public static final String NAME_FLAG = "name"; - - private static final Integer PORT_DEFAULT = 5000; - private static final String PEER_ID_DEFAULT = BootstrapNode.DIGITAL_OCEAN1.getId(); + public static final String PEER_ID_DEFAULT = BootstrapNodes.DIGITAL_OCEAN_1.getId(); private final net.sourceforge.argparse4j.inf.ArgumentParser parser; public ArgumentParser() { parser = ArgumentParsers.newArgumentParser("Bitsquare") .defaultHelp(true) - .description("Bitsquare - The decentralized bitcoin exchange."); + .description("Bitsquare - The decentralized bitcoin exchange"); parser.addArgument("-d", "--" + PEER_ID_FLAG) .setDefault(PEER_ID_DEFAULT) - .help("Seed peer ID."); + .help("Seed peer ID"); parser.addArgument("-p", "--" + PORT_FLAG) - .setDefault(PORT_DEFAULT) - .help("IP port to listen on."); + .setDefault(Node.DEFAULT_PORT) + .help("Port to listen on"); parser.addArgument("-i", "--" + INTERFACE_HINT_FLAG) - .help("Network interface to listen on."); + .help("Network interface to listen on"); parser.addArgument("-n", "--" + NAME_FLAG) - .help("Append name to application name."); + .help("Name to append name to default application name"); } public Namespace parseArgs(String... args) { diff --git a/src/main/java/io/bitsquare/app/cli/SeedNode.java b/src/main/java/io/bitsquare/app/cli/SeedNode.java index 8c20e06289..735b986ca6 100644 --- a/src/main/java/io/bitsquare/app/cli/SeedNode.java +++ b/src/main/java/io/bitsquare/app/cli/SeedNode.java @@ -21,7 +21,7 @@ import io.bitsquare.app.ArgumentParser; import io.bitsquare.msg.actor.DHTManager; import io.bitsquare.msg.actor.command.InitializePeer; import io.bitsquare.msg.actor.event.PeerInitialized; -import io.bitsquare.network.BootstrapNode; +import io.bitsquare.network.BootstrapNodes; import io.bitsquare.network.Node; import java.net.UnknownHostException; @@ -56,10 +56,13 @@ public class SeedNode { interfaceHint = namespace.getString(ArgumentParser.INTERFACE_HINT_FLAG); int serverPort = Integer.valueOf(namespace.getString(ArgumentParser.PORT_FLAG)); - String seedID = namespace.getString(ArgumentParser.PEER_ID_FLAG); + String seedID = BootstrapNodes.LOCALHOST.getId(); + if (namespace.getString(ArgumentParser.PEER_ID_FLAG) != null) { + seedID = namespace.getString(ArgumentParser.PEER_ID_FLAG); + } final Set peerAddresses = new HashSet<>(); - for (Node node : BootstrapNode.values()) { + for (Node node : BootstrapNodes.all()) { if (!node.getId().equals(seedID)) { try { peerAddresses.add(new PeerAddress(Number160.createHash(node.getId()), node.getIp(), diff --git a/src/main/java/io/bitsquare/btc/BitcoinModule.java b/src/main/java/io/bitsquare/btc/BitcoinModule.java index a9601b4adc..c08f2eb562 100644 --- a/src/main/java/io/bitsquare/btc/BitcoinModule.java +++ b/src/main/java/io/bitsquare/btc/BitcoinModule.java @@ -30,15 +30,17 @@ import java.util.Properties; public class BitcoinModule extends AbstractBitsquareModule { - private final BitcoinNetwork defaultNetwork; + private static final BitcoinNetwork DEFAULT_NETWORK = BitcoinNetwork.REGTEST; + + private final BitcoinNetwork network; public BitcoinModule(Properties properties) { - this(properties, BitcoinNetwork.REGTEST); + this(properties, DEFAULT_NETWORK); } - public BitcoinModule(Properties properties, BitcoinNetwork defaultNetwork) { + public BitcoinModule(Properties properties, BitcoinNetwork network) { super(properties); - this.defaultNetwork = defaultNetwork; + this.network = network; } @Override @@ -55,7 +57,7 @@ public class BitcoinModule extends AbstractBitsquareModule { } private NetworkParameters network() { - String networkName = properties.getProperty("networkType", defaultNetwork.name()); + String networkName = properties.getProperty("networkType", network.name()); switch (BitcoinNetwork.valueOf(networkName.toUpperCase())) { case MAINNET: diff --git a/src/main/java/io/bitsquare/msg/DefaultMessageModule.java b/src/main/java/io/bitsquare/msg/DefaultMessageModule.java index ddcad87bd3..4e1e75c2fe 100644 --- a/src/main/java/io/bitsquare/msg/DefaultMessageModule.java +++ b/src/main/java/io/bitsquare/msg/DefaultMessageModule.java @@ -18,7 +18,7 @@ package io.bitsquare.msg; import io.bitsquare.AbstractBitsquareModule; -import io.bitsquare.network.BootstrapNode; +import io.bitsquare.network.BootstrapNodes; import io.bitsquare.network.Node; import com.google.inject.Injector; @@ -44,7 +44,7 @@ public class DefaultMessageModule extends AbstractBitsquareModule implements Mes bind(Node.class) .annotatedWith(Names.named("bootstrapNode")) - .toInstance(BootstrapNode.LOCAL_HOST); + .toInstance(BootstrapNodes.LOCALHOST); } @Override diff --git a/src/main/java/io/bitsquare/network/BootstrapNode.java b/src/main/java/io/bitsquare/network/BootstrapNodes.java similarity index 56% rename from src/main/java/io/bitsquare/network/BootstrapNode.java rename to src/main/java/io/bitsquare/network/BootstrapNodes.java index e675f9af3d..5d8c4b5a75 100644 --- a/src/main/java/io/bitsquare/network/BootstrapNode.java +++ b/src/main/java/io/bitsquare/network/BootstrapNodes.java @@ -17,32 +17,16 @@ package io.bitsquare.network; -public enum BootstrapNode implements Node { - LOCAL_HOST("localhost", "127.0.0.1", 5000), - DIGITAL_OCEAN1("digitalocean1.bitsquare.io", "188.226.179.109", 5000); +import java.util.Arrays; +import java.util.List; - private final String id; - private final String ip; - private final int port; +public interface BootstrapNodes { + Node LOCALHOST = Node.at("localhost", "127.0.0.1"); + Node DIGITAL_OCEAN_1 = Node.at("digitalocean1.bitsquare.io", "188.226.179.109"); - BootstrapNode(String id, String ip, int port) { - this.id = id; - this.ip = ip; - this.port = port; - } - - @Override - public String getId() { - return id; - } - - @Override - public String getIp() { - return ip; - } - - @Override - public int getPort() { - return port; + static List all() { + return Arrays.asList( + LOCALHOST, DIGITAL_OCEAN_1 + ); } } diff --git a/src/main/java/io/bitsquare/network/Node.java b/src/main/java/io/bitsquare/network/Node.java index e0f10b3b07..b975851ca6 100644 --- a/src/main/java/io/bitsquare/network/Node.java +++ b/src/main/java/io/bitsquare/network/Node.java @@ -17,13 +17,66 @@ package io.bitsquare.network; -public interface Node { +import com.google.common.base.Objects; - String getId(); +public final class Node { + public static final int DEFAULT_PORT = 5000; - String getIp(); + private final String id; + private final String ip; + private final int port; - int getPort(); + private Node(String id, String ip, int port) { + this.id = id; + this.ip = ip; + this.port = port; + } + public static Node at(String id, String ip) { + return Node.at(id, ip, DEFAULT_PORT); + } + + public static Node at(String id, String ip, int port) { + return new Node(id, ip, port); + } + + public String getId() { + return id; + } + + public String getIp() { + return ip; + } + + public int getPort() { + return port; + } + + @Override + public boolean equals(Object object) { + if (this == object) + return true; + + if (object == null || getClass() != object.getClass()) + return false; + + Node that = (Node) object; + return Objects.equal(this.id, that.id) && + Objects.equal(this.ip, that.ip) && + Objects.equal(this.port, that.port); + } + + @Override + public int hashCode() { + return Objects.hashCode(id, ip, port); + } + + @Override + public String toString() { + return Objects.toStringHelper(Node.class.getSimpleName()) + .add("id", id) + .add("ip", ip) + .add("port", port) + .toString(); + } } - diff --git a/src/test/java/io/bitsquare/msg/SeedNodeForTesting.java b/src/test/java/io/bitsquare/msg/SeedNodeForTesting.java index cee0df632f..30036be4fc 100644 --- a/src/test/java/io/bitsquare/msg/SeedNodeForTesting.java +++ b/src/test/java/io/bitsquare/msg/SeedNodeForTesting.java @@ -17,6 +17,8 @@ package io.bitsquare.msg; +import io.bitsquare.network.Node; + import net.tomp2p.dht.PeerBuilderDHT; import net.tomp2p.dht.PeerDHT; import net.tomp2p.nat.PeerBuilderNAT; @@ -37,7 +39,7 @@ public class SeedNodeForTesting { public static void main(String[] args) throws Exception { // Define your seed node IP and port // "127.0.0.1" for localhost or SEED_ID_WAN_1 - new SeedNodeForTesting().startSeedNode("localhost", 5000); + new SeedNodeForTesting().startSeedNode("localhost", Node.DEFAULT_PORT); } public Thread startSeedNode(String seedNodeId, int seedNodePort) { diff --git a/src/test/java/io/bitsquare/msg/TomP2PTests.java b/src/test/java/io/bitsquare/msg/TomP2PTests.java index d347af6e76..a2ea4e6092 100644 --- a/src/test/java/io/bitsquare/msg/TomP2PTests.java +++ b/src/test/java/io/bitsquare/msg/TomP2PTests.java @@ -17,8 +17,14 @@ package io.bitsquare.msg; +import io.bitsquare.network.BootstrapNodes; +import io.bitsquare.network.Node; +import io.bitsquare.util.Repeat; + import java.io.IOException; +import java.net.UnknownHostException; + import java.util.HashMap; import java.util.Map; import java.util.concurrent.CountDownLatch; @@ -63,104 +69,59 @@ import static org.junit.Assert.*; * To configure your test environment edit the static fields for id, IP and port. * In the configure method and the connectionType you can define your test scenario. */ - @Ignore public class TomP2PTests { private static final Logger log = LoggerFactory.getLogger(TomP2PTests.class); - /** - * Use UNKNOWN when you want to test the strategy to try first direct, then nat and lat relay - * Use on eof the others when you want to connect only with that mode. Be sure that you can really succeed in that - * mode (e.g. for NAT you need to have a UPnP or NAT PMP enabled router). - */ private enum ConnectionType { - UNKNOWN, - DIRECT, - NAT, - RELAY + UNKNOWN, DIRECT, NAT, RELAY } + // If you want to test in one specific connection mode define it directly, otherwise use UNKNOWN + private static final ConnectionType FORCED_CONNECTION_TYPE = ConnectionType.DIRECT; + + // Typically you run the seed node in localhost to test direct connection. + // If you have a setup where you are not behind a router you can also use a WAN side seed node. + private static final Node BOOTSTRAP_NODE = + (FORCED_CONNECTION_TYPE == ConnectionType.DIRECT) ? BootstrapNodes.LOCALHOST : BootstrapNodes.DIGITAL_OCEAN_1; + + private static final PeerAddress BOOTSTRAP_NODE_ADDRESS; + + static { + try { + BOOTSTRAP_NODE_ADDRESS = new PeerAddress( + Number160.createHash(BOOTSTRAP_NODE.getId()), + BOOTSTRAP_NODE.getIp(), BOOTSTRAP_NODE.getPort(), BOOTSTRAP_NODE.getPort()); + } catch (UnknownHostException ex) { + throw new RuntimeException(BOOTSTRAP_NODE.toString(), ex); + } + } + + // If cache is used tests get faster as it doesn't create and bootstrap a new node at every test. + // Need to observe if it can have some side effects. + private static final boolean CACHE_CLIENTS = true; + + // Use to stress tests by repeating them + private static final int STRESS_TEST_COUNT = 1; + // need to be static to keep them during tests private final static Map cachedPeers = new HashMap<>(); - private String seedId; - private String seedIP; - private int seedPort; private PeerDHT peer1DHT; private PeerDHT peer2DHT; private int client1Port; private int client2Port; private ConnectionType resolvedConnectionType; - - /////////////////////////////////////////////////////////////////////////////////////////// - // Configure - /////////////////////////////////////////////////////////////////////////////////////////// - - // Setup your seed node - private final static String SEED_ID_WAN_1 = "digitalocean1.bitsquare.io"; - private final static String SEED_IP_WAN_1 = "188.226.179.109"; - private final static int SEED_PORT_WAN_1 = 5000; - - // Setup a second seed node used in some tests - private final static String SEED_ID_WAN_2 = "digitalocean2.bitsquare.io"; - private final static String SEED_IP_WAN_2 = "188.226.179.109"; - private final static int SEED_PORT_WAN_2 = 5001; - - // If you want to test in one specific connection mode define it directly, otherwise use UNKNOWN - private final ConnectionType forcedConnectionType = ConnectionType.DIRECT; - - // In port forwarding mode the isSuccess returns false, but the DHT operations succeeded. - // Needs investigation why. Will be removed as far its fixed. - private boolean ignoreSuccessTests = false; - - // If cache is used tests get faster as it doesn't create and bootstrap a new node at every test. - // Need to observe if it can have some side effects. - private boolean cacheClients = true; - - // Use that to stress test with repeated run of the test method body - private int stressTestLoopCount = 1; - @Before - public void configure() { - // Typically you run the seed node in localhost to test direct connection. - // If you have a setup where you are not behind a router you can also use a WAN side seed node. - if (forcedConnectionType == ConnectionType.DIRECT) { - seedId = "localhost"; - seedIP = "127.0.0.1"; - seedPort = 5000; - } - else { - seedId = SEED_ID_WAN_1; - seedIP = SEED_IP_WAN_1; - seedPort = SEED_PORT_WAN_1; - } - - // Only in NAT mode we have to deal with that bug. - if (forcedConnectionType == ConnectionType.NAT || resolvedConnectionType == ConnectionType.NAT) - ignoreSuccessTests = true; - + public void setUp() { client1Port = getNewRandomPort(); client2Port = getNewRandomPort(); } - private int getNewRandomPort() { - // new Ports().tcpPort() returns a random port - int newPort = new Ports().tcpPort(); - while (newPort == client1Port || newPort == client2Port) - newPort = new Ports().tcpPort(); - - return newPort; - } - - - /////////////////////////////////////////////////////////////////////////////////////////// - // Tests - /////////////////////////////////////////////////////////////////////////////////////////// - @After - public void shutdown() { - if (!cacheClients) { + public void tearDown() { + if (!CACHE_CLIENTS) { if (peer1DHT != null) peer1DHT.shutdown().awaitUninterruptibly(); if (peer2DHT != null) @@ -169,171 +130,134 @@ public class TomP2PTests { } @Test + @Repeat(STRESS_TEST_COUNT) public void bootstrapInUnknownMode() throws Exception { - for (int i = 0; i < stressTestLoopCount; i++) { - configure(); - if (forcedConnectionType == ConnectionType.UNKNOWN) - assertNotNull(bootstrapInUnknownMode("node_1", client1Port)); - - shutdown(); - } + if (FORCED_CONNECTION_TYPE == ConnectionType.UNKNOWN) + assertNotNull(bootstrapInUnknownMode("node_1", client1Port)); } @Test + @Repeat(STRESS_TEST_COUNT) public void testBootstrapDirectConnection() throws Exception { - for (int i = 0; i < stressTestLoopCount; i++) { - configure(); - if (forcedConnectionType == ConnectionType.DIRECT) - assertNotNull(bootstrapDirectConnection("node_1", client1Port)); - - shutdown(); - } + if (FORCED_CONNECTION_TYPE == ConnectionType.DIRECT) + assertNotNull(bootstrapDirectConnection("node_1", client1Port)); } @Test + @Repeat(STRESS_TEST_COUNT) public void testBootstrapWithPortForwarding() throws Exception { - for (int i = 0; i < stressTestLoopCount; i++) { - configure(); - if (forcedConnectionType == ConnectionType.NAT) - assertNotNull(bootstrapWithPortForwarding("node_1", client1Port)); - - shutdown(); - } + if (FORCED_CONNECTION_TYPE == ConnectionType.NAT) + assertNotNull(bootstrapWithPortForwarding("node_1", client1Port)); } @Test + @Repeat(STRESS_TEST_COUNT) public void testBootstrapInRelayMode() throws Exception { - for (int i = 0; i < stressTestLoopCount; i++) { - configure(); - if (forcedConnectionType == ConnectionType.RELAY) + if (FORCED_CONNECTION_TYPE == ConnectionType.RELAY) assertNotNull(bootstrapInRelayMode("node_1", client1Port)); - - shutdown(); - } } @Test + @Repeat(STRESS_TEST_COUNT) public void testPut() throws Exception { - for (int i = 0; i < stressTestLoopCount; i++) { - configure(); - peer1DHT = getDHTPeer("node_1", client1Port); FuturePut futurePut = peer1DHT.put(Number160.createHash("key")).data(new Data("hallo")).start(); futurePut.awaitUninterruptibly(); - if (!ignoreSuccessTests) + if (shouldEvaluateSuccess()) assertTrue(futurePut.isSuccess()); - - shutdown(); - } } @Test + @Repeat(STRESS_TEST_COUNT) public void testPutGet() throws Exception { - for (int i = 0; i < stressTestLoopCount; i++) { - configure(); - peer1DHT = getDHTPeer("node_1", client1Port); - FuturePut futurePut = peer1DHT.put(Number160.createHash("key")).data(new Data("hallo")).start(); - futurePut.awaitUninterruptibly(); - if (!ignoreSuccessTests) - assertTrue(futurePut.isSuccess()); + peer1DHT = getDHTPeer("node_1", client1Port); + FuturePut futurePut = peer1DHT.put(Number160.createHash("key")).data(new Data("hallo")).start(); + futurePut.awaitUninterruptibly(); + if (shouldEvaluateSuccess()) + assertTrue(futurePut.isSuccess()); - peer2DHT = getDHTPeer("node_2", client2Port); - FutureGet futureGet = peer2DHT.get(Number160.createHash("key")).start(); - futureGet.awaitUninterruptibly(); - if (!ignoreSuccessTests) - assertTrue(futureGet.isSuccess()); - assertEquals("hallo", futureGet.data().object()); - - shutdown(); - } + peer2DHT = getDHTPeer("node_2", client2Port); + FutureGet futureGet = peer2DHT.get(Number160.createHash("key")).start(); + futureGet.awaitUninterruptibly(); + if (shouldEvaluateSuccess()) + assertTrue(futureGet.isSuccess()); + assertEquals("hallo", futureGet.data().object()); } @Test + @Repeat(STRESS_TEST_COUNT) public void testAdd() throws Exception { - for (int i = 0; i < stressTestLoopCount; i++) { - configure(); - peer1DHT = getDHTPeer("node_1", client1Port); - FuturePut futurePut1 = peer1DHT.add(Number160.createHash("locationKey")).data(new Data("hallo1")).start(); - futurePut1.awaitUninterruptibly(); - if (!ignoreSuccessTests) - assertTrue(futurePut1.isSuccess()); + peer1DHT = getDHTPeer("node_1", client1Port); + FuturePut futurePut1 = peer1DHT.add(Number160.createHash("locationKey")).data(new Data("hallo1")).start(); + futurePut1.awaitUninterruptibly(); + if (shouldEvaluateSuccess()) + assertTrue(futurePut1.isSuccess()); - FuturePut futurePut2 = peer1DHT.add(Number160.createHash("locationKey")).data(new Data("hallo2")).start(); - futurePut2.awaitUninterruptibly(); - if (!ignoreSuccessTests) - assertTrue(futurePut2.isSuccess()); - - shutdown(); - } + FuturePut futurePut2 = peer1DHT.add(Number160.createHash("locationKey")).data(new Data("hallo2")).start(); + futurePut2.awaitUninterruptibly(); + if (shouldEvaluateSuccess()) + assertTrue(futurePut2.isSuccess()); } @Test + @Repeat(STRESS_TEST_COUNT) public void testAddGet() throws Exception { - for (int i = 0; i < stressTestLoopCount; i++) { - configure(); - peer1DHT = getDHTPeer("node_1", client1Port); - FuturePut futurePut1 = peer1DHT.add(Number160.createHash("locationKey")).data(new Data("hallo1")).start(); - futurePut1.awaitUninterruptibly(); - if (!ignoreSuccessTests) - assertTrue(futurePut1.isSuccess()); + peer1DHT = getDHTPeer("node_1", client1Port); + FuturePut futurePut1 = peer1DHT.add(Number160.createHash("locationKey")).data(new Data("hallo1")).start(); + futurePut1.awaitUninterruptibly(); + if (shouldEvaluateSuccess()) + assertTrue(futurePut1.isSuccess()); - FuturePut futurePut2 = peer1DHT.add(Number160.createHash("locationKey")).data(new Data("hallo2")).start(); - futurePut2.awaitUninterruptibly(); - if (!ignoreSuccessTests) - assertTrue(futurePut2.isSuccess()); + FuturePut futurePut2 = peer1DHT.add(Number160.createHash("locationKey")).data(new Data("hallo2")).start(); + futurePut2.awaitUninterruptibly(); + if (shouldEvaluateSuccess()) + assertTrue(futurePut2.isSuccess()); - peer2DHT = getDHTPeer("node_2", client2Port); - FutureGet futureGet = peer2DHT.get(Number160.createHash("locationKey")).all().start(); - futureGet.awaitUninterruptibly(); - if (!ignoreSuccessTests) - assertTrue(futureGet.isSuccess()); + peer2DHT = getDHTPeer("node_2", client2Port); + FutureGet futureGet = peer2DHT.get(Number160.createHash("locationKey")).all().start(); + futureGet.awaitUninterruptibly(); + if (shouldEvaluateSuccess()) + assertTrue(futureGet.isSuccess()); - assertTrue(futureGet.dataMap().values().contains(new Data("hallo1"))); - assertTrue(futureGet.dataMap().values().contains(new Data("hallo2"))); - assertTrue(futureGet.dataMap().values().size() == 2); - - shutdown(); - } + assertTrue(futureGet.dataMap().values().contains(new Data("hallo1"))); + assertTrue(futureGet.dataMap().values().contains(new Data("hallo2"))); + assertTrue(futureGet.dataMap().values().size() == 2); } @Test + @Repeat(STRESS_TEST_COUNT) public void testAddRemove() throws Exception { - for (int i = 0; i < stressTestLoopCount; i++) { - configure(); - peer1DHT = getDHTPeer("node_1", client1Port); - FuturePut futurePut1 = peer1DHT.add(Number160.createHash("locationKey")).data(new Data("hallo1")).start(); - futurePut1.awaitUninterruptibly(); - if (!ignoreSuccessTests) - assertTrue(futurePut1.isSuccess()); + peer1DHT = getDHTPeer("node_1", client1Port); + FuturePut futurePut1 = peer1DHT.add(Number160.createHash("locationKey")).data(new Data("hallo1")).start(); + futurePut1.awaitUninterruptibly(); + if (shouldEvaluateSuccess()) + assertTrue(futurePut1.isSuccess()); - FuturePut futurePut2 = peer1DHT.add(Number160.createHash("locationKey")).data(new Data("hallo2")).start(); - futurePut2.awaitUninterruptibly(); - if (!ignoreSuccessTests) - assertTrue(futurePut2.isSuccess()); + FuturePut futurePut2 = peer1DHT.add(Number160.createHash("locationKey")).data(new Data("hallo2")).start(); + futurePut2.awaitUninterruptibly(); + if (shouldEvaluateSuccess()) + assertTrue(futurePut2.isSuccess()); - peer2DHT = getDHTPeer("node_2", client2Port); - Number160 contentKey = new Data("hallo1").hash(); - FutureRemove futureRemove = peer2DHT.remove(Number160.createHash("locationKey")).contentKey(contentKey) - .start(); - futureRemove.awaitUninterruptibly(); + peer2DHT = getDHTPeer("node_2", client2Port); + Number160 contentKey = new Data("hallo1").hash(); + FutureRemove futureRemove = peer2DHT.remove(Number160.createHash("locationKey")).contentKey(contentKey) + .start(); + futureRemove.awaitUninterruptibly(); - // That fails sometimes in direct mode and NAT - if (!ignoreSuccessTests) - assertTrue(futureRemove.isSuccess()); + // That fails sometimes in direct mode and NAT + if (shouldEvaluateSuccess()) + assertTrue(futureRemove.isSuccess()); - FutureGet futureGet = peer2DHT.get(Number160.createHash("locationKey")).all().start(); - futureGet.awaitUninterruptibly(); - if (!ignoreSuccessTests) - assertTrue(futureGet.isSuccess()); + FutureGet futureGet = peer2DHT.get(Number160.createHash("locationKey")).all().start(); + futureGet.awaitUninterruptibly(); + if (shouldEvaluateSuccess()) + assertTrue(futureGet.isSuccess()); - assertTrue(futureGet.dataMap().values().contains(new Data("hallo2"))); - assertTrue(futureGet.dataMap().values().size() == 1); - - shutdown(); - } + assertTrue(futureGet.dataMap().values().contains(new Data("hallo2"))); + assertTrue(futureGet.dataMap().values().size() == 1); } @@ -341,83 +265,62 @@ public class TomP2PTests { // So if both clients are behind NAT they cannot send direct message to each other. // That will probably be fixed in a future version of TomP2P @Test + @Repeat(STRESS_TEST_COUNT) public void testSendDirectBetweenLocalPeers() throws Exception { - for (int i = 0; i < stressTestLoopCount; i++) { - configure(); - if (forcedConnectionType != ConnectionType.NAT && resolvedConnectionType != ConnectionType.NAT) { - peer1DHT = getDHTPeer("node_1", client1Port); - peer2DHT = getDHTPeer("node_2", client2Port); + if (FORCED_CONNECTION_TYPE != ConnectionType.NAT && resolvedConnectionType != ConnectionType.NAT) { + peer1DHT = getDHTPeer("node_1", client1Port); + peer2DHT = getDHTPeer("node_2", client2Port); - final CountDownLatch countDownLatch = new CountDownLatch(1); + final CountDownLatch countDownLatch = new CountDownLatch(1); - final StringBuilder result = new StringBuilder(); - peer2DHT.peer().objectDataReply((sender, request) -> { - countDownLatch.countDown(); - result.append(String.valueOf(request)); - return "pong"; - }); - FuturePeerConnection futurePeerConnection = peer1DHT.peer().createPeerConnection(peer2DHT.peer() - .peerAddress(), 500); - FutureDirect futureDirect = peer1DHT.peer().sendDirect(futurePeerConnection).object("hallo").start(); - futureDirect.awaitUninterruptibly(); + final StringBuilder result = new StringBuilder(); + peer2DHT.peer().objectDataReply((sender, request) -> { + countDownLatch.countDown(); + result.append(String.valueOf(request)); + return "pong"; + }); + FuturePeerConnection futurePeerConnection = peer1DHT.peer().createPeerConnection(peer2DHT.peer() + .peerAddress(), 500); + FutureDirect futureDirect = peer1DHT.peer().sendDirect(futurePeerConnection).object("hallo").start(); + futureDirect.awaitUninterruptibly(); - countDownLatch.await(3, TimeUnit.SECONDS); - if (countDownLatch.getCount() > 0) - Assert.fail("The test method did not complete successfully!"); + countDownLatch.await(3, TimeUnit.SECONDS); + if (countDownLatch.getCount() > 0) + Assert.fail("The test method did not complete successfully!"); - assertEquals("hallo", result.toString()); - assertTrue(futureDirect.isSuccess()); - log.debug(futureDirect.object().toString()); - assertEquals("pong", futureDirect.object()); - } - - shutdown(); + assertEquals("hallo", result.toString()); + assertTrue(futureDirect.isSuccess()); + log.debug(futureDirect.object().toString()); + assertEquals("pong", futureDirect.object()); } } // That test should always succeed as we use the server seed node as receiver. // A node can send a message to another peer which is not in the same LAN. @Test + @Repeat(STRESS_TEST_COUNT) public void testSendDirectToSeedNode() throws Exception { - for (int i = 0; i < stressTestLoopCount; i++) { - configure(); - peer1DHT = getDHTPeer("node_1", client1Port); - PeerAddress reachablePeerAddress = new PeerAddress(Number160.createHash(seedId), seedIP, seedPort, - seedPort); + peer1DHT = getDHTPeer("node_1", client1Port); - FuturePeerConnection futurePeerConnection = peer1DHT.peer().createPeerConnection - (reachablePeerAddress, 500); - FutureDirect futureDirect = peer1DHT.peer().sendDirect(futurePeerConnection).object("hallo").start(); - futureDirect.awaitUninterruptibly(); - assertTrue(futureDirect.isSuccess()); - assertEquals("pong", futureDirect.object()); - - shutdown(); - } + FuturePeerConnection futurePeerConnection = + peer1DHT.peer().createPeerConnection(BOOTSTRAP_NODE_ADDRESS, 500); + FutureDirect futureDirect = peer1DHT.peer().sendDirect(futurePeerConnection).object("hallo").start(); + futureDirect.awaitUninterruptibly(); + assertTrue(futureDirect.isSuccess()); + assertEquals("pong", futureDirect.object()); } - /////////////////////////////////////////////////////////////////////////////////////////// - // Bootstrapping - /////////////////////////////////////////////////////////////////////////////////////////// - private Peer bootstrapDirectConnection(String clientId, int clientPort) { - return bootstrapDirectConnection(clientId, clientPort, seedId, seedIP, seedPort); - } - - private Peer bootstrapDirectConnection(String clientId, int clientPort, String seedNodeId, - String seedNodeIP, int seedNodePort) { final String id = clientId + clientPort; - if (cacheClients && cachedPeers.containsKey(id)) { + if (CACHE_CLIENTS && cachedPeers.containsKey(id)) { return cachedPeers.get(id); } Peer peer = null; try { peer = new PeerBuilder(Number160.createHash(clientId)).ports(clientPort).start(); - PeerAddress masterNodeAddress = new PeerAddress(Number160.createHash(seedNodeId), seedNodeIP, seedNodePort, - seedNodePort); - FutureDiscover futureDiscover = peer.discover().peerAddress(masterNodeAddress).start(); + FutureDiscover futureDiscover = peer.discover().peerAddress(BOOTSTRAP_NODE_ADDRESS).start(); futureDiscover.awaitUninterruptibly(); if (futureDiscover.isSuccess()) { log.info("Discover with direct connection successful. Address = " + futureDiscover.peerAddress()); @@ -440,28 +343,21 @@ public class TomP2PTests { } private Peer bootstrapWithPortForwarding(String clientId, int clientPort) { - return bootstrapWithPortForwarding(clientId, clientPort, seedId, seedIP, seedPort); - } - - private Peer bootstrapWithPortForwarding(String clientId, int clientPort, String seedNodeId, - String seedNodeIP, int seedNodePort) { final String id = clientId + clientPort; - if (cacheClients && cachedPeers.containsKey(id)) { + if (CACHE_CLIENTS && cachedPeers.containsKey(id)) { return cachedPeers.get(id); } Peer peer = null; try { peer = new PeerBuilder(Number160.createHash(clientId)).ports(clientPort).behindFirewall().start(); PeerNAT peerNAT = new PeerBuilderNAT(peer).start(); - PeerAddress masterNodeAddress = new PeerAddress(Number160.createHash(seedNodeId), seedNodeIP, seedNodePort, - seedNodePort); - FutureDiscover futureDiscover = peer.discover().peerAddress(masterNodeAddress).start(); + FutureDiscover futureDiscover = peer.discover().peerAddress(BOOTSTRAP_NODE_ADDRESS).start(); FutureNAT futureNAT = peerNAT.startSetupPortforwarding(futureDiscover); futureNAT.awaitUninterruptibly(); if (futureNAT.isSuccess()) { log.info("Automatic port forwarding is setup. Now we do a futureDiscover again. Address = " + futureNAT.peerAddress()); - futureDiscover = peer.discover().peerAddress(masterNodeAddress).start(); + futureDiscover = peer.discover().peerAddress(BOOTSTRAP_NODE_ADDRESS).start(); futureDiscover.awaitUninterruptibly(); if (futureDiscover.isSuccess()) { log.info("Discover with automatic port forwarding was successful. Address = " + futureDiscover @@ -493,13 +389,8 @@ public class TomP2PTests { } private Peer bootstrapInRelayMode(String clientId, int clientPort) { - return bootstrapInRelayMode(clientId, clientPort, seedId, seedIP, seedPort); - } - - private Peer bootstrapInRelayMode(String clientId, int clientPort, String seedNodeId, - String seedNodeIP, int seedNodePort) { final String id = clientId + clientPort; - if (cacheClients && cachedPeers.containsKey(id)) { + if (CACHE_CLIENTS && cachedPeers.containsKey(id)) { return cachedPeers.get(id); } @@ -507,9 +398,7 @@ public class TomP2PTests { try { peer = new PeerBuilder(Number160.createHash(clientId)).ports(clientPort).behindFirewall().start(); PeerNAT peerNAT = new PeerBuilderNAT(peer).start(); - PeerAddress masterNodeAddress = new PeerAddress(Number160.createHash(seedNodeId), seedNodeIP, seedNodePort, - seedNodePort); - FutureDiscover futureDiscover = peer.discover().peerAddress(masterNodeAddress).start(); + FutureDiscover futureDiscover = peer.discover().peerAddress(BOOTSTRAP_NODE_ADDRESS).start(); FutureNAT futureNAT = peerNAT.startSetupPortforwarding(futureDiscover); FutureRelayNAT futureRelayNAT = peerNAT.startRelay(futureDiscover, futureNAT); futureRelayNAT.awaitUninterruptibly(); @@ -536,63 +425,61 @@ public class TomP2PTests { } private Peer bootstrapInUnknownMode(String clientId, int clientPort) { - return bootstrapInUnknownMode(clientId, clientPort, seedId, seedIP, seedPort); - } - - private Peer bootstrapInUnknownMode(String clientId, int clientPort, String seedNodeId, - String seedNodeIP, int seedNodePort) { resolvedConnectionType = ConnectionType.DIRECT; - Peer peer = bootstrapDirectConnection(clientId, clientPort, seedNodeId, seedNodeIP, seedNodePort); + Peer peer = bootstrapDirectConnection(clientId, clientPort); if (peer != null) return peer; resolvedConnectionType = ConnectionType.NAT; - peer = bootstrapWithPortForwarding(clientId, clientPort, seedNodeId, seedNodeIP, seedNodePort); + peer = bootstrapWithPortForwarding(clientId, clientPort); if (peer != null) return peer; resolvedConnectionType = ConnectionType.RELAY; - peer = bootstrapInRelayMode(clientId, clientPort, seedNodeId, seedNodeIP, seedNodePort); + peer = bootstrapInRelayMode(clientId, clientPort); if (peer != null) return peer; else - log.error("Bootstrapping in all modes failed. Check if the seed node is running. " + - "seedNodeId= " + seedNodeId + - "seedNodeIP= " + seedNodeIP + - "seedNodePort= " + seedNodePort); + log.error("Bootstrapping in all modes failed. Is bootstrap node " + BOOTSTRAP_NODE + "running?"); resolvedConnectionType = null; return peer; } private PeerDHT getDHTPeer(String clientId, int clientPort) { - return getDHTPeer(clientId, clientPort, seedId, seedIP, seedPort); - } - - private PeerDHT getDHTPeer(String clientId, int clientPort, String seedNodeId, - String seedNodeIP, int seedNodePort) { Peer peer; - if (forcedConnectionType == ConnectionType.DIRECT) { - peer = bootstrapDirectConnection(clientId, clientPort, seedNodeId, seedNodeIP, seedNodePort); + if (FORCED_CONNECTION_TYPE == ConnectionType.DIRECT) { + peer = bootstrapDirectConnection(clientId, clientPort); } - else if (forcedConnectionType == ConnectionType.NAT) { - peer = bootstrapWithPortForwarding(clientId, clientPort, seedNodeId, seedNodeIP, seedNodePort); + else if (FORCED_CONNECTION_TYPE == ConnectionType.NAT) { + peer = bootstrapWithPortForwarding(clientId, clientPort); } - else if (forcedConnectionType == ConnectionType.RELAY) { - peer = bootstrapInRelayMode(clientId, clientPort, seedNodeId, seedNodeIP, seedNodePort); + else if (FORCED_CONNECTION_TYPE == ConnectionType.RELAY) { + peer = bootstrapInRelayMode(clientId, clientPort); } else { - peer = bootstrapInUnknownMode(clientId, clientPort, seedNodeId, seedNodeIP, seedNodePort); + peer = bootstrapInUnknownMode(clientId, clientPort); } if (peer == null) - Assert.fail("Bootstrapping failed. Check if the seed node is running. " + - "forcedConnectionType= " + forcedConnectionType + - " resolvedConnectionType= " + resolvedConnectionType + - " seedNodeId= " + seedNodeId + - " seedNodeIP= " + seedNodeIP + - " seedNodePort= " + seedNodePort); + Assert.fail("Bootstrapping failed." + + " forcedConnectionType= " + FORCED_CONNECTION_TYPE + + " resolvedConnectionType= " + resolvedConnectionType + "." + + " Is bootstrap node " + BOOTSTRAP_NODE + "running?"); return new PeerBuilderDHT(peer).start(); } + + private int getNewRandomPort() { + // new Ports().tcpPort() returns a random port + int newPort = new Ports().tcpPort(); + while (newPort == client1Port || newPort == client2Port) + newPort = new Ports().tcpPort(); + + return newPort; + } + + private boolean shouldEvaluateSuccess() { + return FORCED_CONNECTION_TYPE == ConnectionType.NAT || resolvedConnectionType == ConnectionType.NAT; + } } diff --git a/src/test/java/io/bitsquare/network/NodeTests.java b/src/test/java/io/bitsquare/network/NodeTests.java new file mode 100644 index 0000000000..5c4d5433cd --- /dev/null +++ b/src/test/java/io/bitsquare/network/NodeTests.java @@ -0,0 +1,54 @@ +/* + * This file is part of Bitsquare. + * + * Bitsquare 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. + * + * Bitsquare 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 Bitsquare. If not, see . + */ + +package io.bitsquare.network; + +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +public class NodeTests { + + @Test + public void testEqualsAndHashCode() { + Node node1a = Node.at("bitsquare1.example.com", "203.0.113.1"); + Node node1b = Node.at("bitsquare1.example.com", "203.0.113.1"); + + assertThat(node1a, equalTo(node1a)); + + assertThat(node1a, equalTo(node1b)); + assertThat(node1b, equalTo(node1a)); + + assertThat(node1a, not((Object) equalTo(null))); + assertThat(node1a, not((Object) equalTo("not a node"))); + + assertThat(node1a, not(equalTo(Node.at("bitsquare2.example.com", node1a.getIp())))); + assertThat(node1a, not(equalTo(Node.at(node1a.getId(), "203.0.113.2")))); + assertThat(node1a, not(equalTo(Node.at(node1a.getId(), node1a.getIp(), Node.DEFAULT_PORT + 1)))); + + Node node2 = Node.at("bitsquare2.example.com", "203.0.113.2"); + assertThat(node1a.hashCode(), equalTo(node1b.hashCode())); + assertThat(node1a.hashCode(), not(equalTo(node2.hashCode()))); + } + + @Test + public void testToString() { + Node node = Node.at("bitsquare1.example.com", "203.0.113.1", 5001); + assertThat(node.toString(), equalTo("Node{id=bitsquare1.example.com, ip=203.0.113.1, port=5001}")); + } +} \ No newline at end of file diff --git a/src/test/java/io/bitsquare/util/Repeat.java b/src/test/java/io/bitsquare/util/Repeat.java new file mode 100644 index 0000000000..d67c8be70b --- /dev/null +++ b/src/test/java/io/bitsquare/util/Repeat.java @@ -0,0 +1,38 @@ +/* + * This file is part of Bitsquare. + * + * Bitsquare 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. + * + * Bitsquare 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 Bitsquare. If not, see . + */ + +package io.bitsquare.util; + +import java.lang.annotation.ElementType; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Method-level annotation to be used in connection with {@link RepeatRule} to cause a + * given {@link org.junit.Test} method to be repeated a specified number of times. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface Repeat { + + /** + * Specifies the number of times to repeat the annotated {@link org.junit.Test}. + */ + int value(); +} \ No newline at end of file diff --git a/src/test/java/io/bitsquare/util/RepeatRule.java b/src/test/java/io/bitsquare/util/RepeatRule.java new file mode 100644 index 0000000000..6505952950 --- /dev/null +++ b/src/test/java/io/bitsquare/util/RepeatRule.java @@ -0,0 +1,57 @@ +/* + * This file is part of Bitsquare. + * + * Bitsquare 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. + * + * Bitsquare 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 Bitsquare. If not, see . + */ + +package io.bitsquare.util; + +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +/** + * @see {@link Repeat} + */ +public class RepeatRule implements TestRule { + + private static class RepeatStatement extends Statement { + + private final int times; + private final Statement statement; + + private RepeatStatement(int times, Statement statement) { + this.times = times; + this.statement = statement; + } + + @Override + public void evaluate() throws Throwable { + for (int i = 0; i < times; i++) { + statement.evaluate(); + } + } + } + + @Override + public Statement apply(Statement statement, Description description) { + Statement result = statement; + Repeat repeat = description.getAnnotation(Repeat.class); + if (repeat != null) { + int times = repeat.value(); + result = new RepeatStatement(times, statement); + } + return result; + } +} \ No newline at end of file diff --git a/src/test/java/io/bitsquare/util/RepeatRuleTests.java b/src/test/java/io/bitsquare/util/RepeatRuleTests.java new file mode 100644 index 0000000000..f9278d3c32 --- /dev/null +++ b/src/test/java/io/bitsquare/util/RepeatRuleTests.java @@ -0,0 +1,68 @@ +/* + * This file is part of Bitsquare. + * + * Bitsquare 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. + * + * Bitsquare 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 Bitsquare. If not, see . + */ + +package io.bitsquare.util; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.*; + +public class RepeatRuleTests { + + private static final int EXPECTED_COUNT = 10; + private static int ACTUAL_BEFORE_COUNT; + private static int ACTUAL_TEST_COUNT; + private static int ACTUAL_AFTER_COUNT; + + public @Rule RepeatRule repeatRule = new RepeatRule(); + + @BeforeClass + public static void beforeTests() { + ACTUAL_BEFORE_COUNT = 0; + ACTUAL_TEST_COUNT = 0; + ACTUAL_AFTER_COUNT = 0; + } + + @Before + public void setUp() { + ACTUAL_BEFORE_COUNT++; + } + + @Test + @Repeat(EXPECTED_COUNT) + public void shouldBeRepeated() { + ACTUAL_TEST_COUNT++; + } + + @After + public void tearDown() { + ACTUAL_AFTER_COUNT++; + } + + @AfterClass + public static void afterTests() { + assertThat(ACTUAL_BEFORE_COUNT, equalTo(EXPECTED_COUNT)); + assertThat(ACTUAL_TEST_COUNT, equalTo(EXPECTED_COUNT)); + assertThat(ACTUAL_AFTER_COUNT, equalTo(EXPECTED_COUNT)); + } +}