Package net.tomp2p.examples

Source Code of net.tomp2p.examples.TomP2PTests

/*
* 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 <http://www.gnu.org/licenses/>.
*/

package net.tomp2p.examples;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import net.tomp2p.connection.ChannelClientConfiguration;
import net.tomp2p.connection.Ports;
import net.tomp2p.dht.*;
import net.tomp2p.futures.FutureBootstrap;
import net.tomp2p.futures.FutureDirect;
import net.tomp2p.futures.FutureDiscover;
import net.tomp2p.futures.FuturePeerConnection;
import net.tomp2p.nat.FutureNAT;
import net.tomp2p.nat.FutureRelayNAT;
import net.tomp2p.nat.PeerBuilderNAT;
import net.tomp2p.nat.PeerNAT;
import net.tomp2p.p2p.Peer;
import net.tomp2p.p2p.PeerBuilder;
import net.tomp2p.peers.Number160;
import net.tomp2p.peers.PeerAddress;
import net.tomp2p.peers.PeerMap;
import net.tomp2p.peers.PeerMapConfiguration;
import net.tomp2p.rpc.ObjectDataReply;
import net.tomp2p.storage.Data;

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static org.junit.Assert.*;

/**
* Test bootstrapping, DHT operations like put/get/add/remove and sendDirect in both LAN and WAN environment
* Test scenarios in direct connection, auto port forwarding or relay mode.
* <p/>
* The start a seed node code use the {@link SeedNodeForTesting} class.
* <p/>
* 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
    }

    // need to be static to keep them during tests
    //private final static Map<String, Peer> cachedPeers = new HashMap<String, Peer>();

    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
    final static String SEED_ID_WAN_1 = "seed";
    private final static String SEED_IP_WAN_1 = "127.0.0.1";
    private final static int SEED_PORT_WAN_1 = 5000;

    // If you want to test in one specific connection mode define it directly, otherwise use UNKNOWN
    private final ConnectionType forcedConnectionType = ConnectionType.DIRECT;

    // 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.

    // Use that to stress test with repeated run of the test method body
    private int stressTestLoopCount = 100;

    @Before
    public void configure() {
      seedId = SEED_ID_WAN_1;
        // 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) {
            seedIP = "127.0.0.1";
            seedPort = 5000;
        }
        else {
            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;

        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 (peer1DHT != null)
          peer1DHT.shutdown().awaitUninterruptibly();
        if (peer2DHT != null)
            peer2DHT.shutdown().awaitUninterruptibly();
    }

    @Test
    public void bootstrapInUnknownMode() throws Exception {
        for (int i = 0; i < stressTestLoopCount; i++) {
            configure();
            if (forcedConnectionType == ConnectionType.UNKNOWN)
                assertNotNull(bootstrapInUnknownMode("node_1", client1Port));

            shutdown();
        }
    }

    @Test
    public void testBootstrapDirectConnection() throws Exception {
        for (int i = 0; i < stressTestLoopCount; i++) {
            configure();
            if (forcedConnectionType == ConnectionType.DIRECT)
                assertNotNull(bootstrapDirectConnection("node_1", client1Port));

            shutdown();
        }
    }

    @Test
    public void testBootstrapWithPortForwarding() throws Exception {
        for (int i = 0; i < stressTestLoopCount; i++) {
            configure();
            if (forcedConnectionType == ConnectionType.NAT)
                assertNotNull(bootstrapWithPortForwarding("node_1", client1Port));

            shutdown();
        }
    }

    @Test
    public void testBootstrapInRelayMode() throws Exception {
        for (int i = 0; i < stressTestLoopCount; i++) {
            configure();
            if (forcedConnectionType == ConnectionType.RELAY)
                assertNotNull(bootstrapInRelayMode("node_1", client1Port));

            shutdown();
        }
    }

    @Test
    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();
            assertTrue(futurePut.isSuccess());

            shutdown();
        }
    }

    @Test
    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();
            assertTrue(futurePut.isSuccess());

            peer2DHT = getDHTPeer("node_2", client2Port);
            FutureGet futureGet = peer2DHT.get(Number160.createHash("key")).start();
            futureGet.awaitUninterruptibly();
            assertTrue(futureGet.isSuccess());
            assertEquals("hallo", futureGet.data().object());

            shutdown();
        }
    }

    @Test
    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();
            assertTrue(futurePut1.isSuccess());

            FuturePut futurePut2 = peer1DHT.add(Number160.createHash("locationKey")).data(new Data("hallo2")).start();
            futurePut2.awaitUninterruptibly();
            assertTrue(futurePut2.isSuccess());

            shutdown();
        }
    }

    @Test
    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();
            assertTrue(futurePut1.isSuccess());

            FuturePut futurePut2 = peer1DHT.add(Number160.createHash("locationKey")).data(new Data("hallo2")).start();
            futurePut2.awaitUninterruptibly();
            assertTrue(futurePut2.isSuccess());

            peer2DHT = getDHTPeer("node_2", client2Port);
            FutureGet futureGet = peer2DHT.get(Number160.createHash("locationKey")).all().start();
            futureGet.awaitUninterruptibly();
            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();
        }
    }

    @Test
    public void testAddRemove() throws Exception {
        for (int i = 0; i < stressTestLoopCount; i++) {
            configure();
           
            if(forcedConnectionType == ConnectionType.DIRECT) {
              SeedNodeForTesting.main(null);
            }
           
            peer1DHT = getDHTPeer("node_1" + i, client1Port);
            FuturePut futurePut1 = peer1DHT.add(Number160.createHash("locationKey")).data(new Data("hallo1")).start();
            futurePut1.awaitUninterruptibly();
            futurePut1.awaitListenersUninterruptibly();
            assertTrue(futurePut1.isSuccess());

            FuturePut futurePut2 = peer1DHT.add(Number160.createHash("locationKey")).data(new Data("hallo2")).start();
            futurePut2.awaitUninterruptibly();
            futurePut2.awaitListenersUninterruptibly();
            assertTrue(futurePut2.isSuccess());

            peer2DHT = getDHTPeer("node_2" + i, client2Port);
            Number160 contentKey = new Data("hallo1").hash();
            FutureRemove futureRemove = peer2DHT.remove(Number160.createHash("locationKey")).contentKey(contentKey)
                                                .start();
            futureRemove.awaitUninterruptibly();
            futureRemove.awaitListenersUninterruptibly();

            // That fails sometimes in direct mode and NAT
            assertTrue(futureRemove.isSuccess());

            FutureGet futureGet = peer2DHT.get(Number160.createHash("locationKey")).all().start();
            futureGet.awaitUninterruptibly();
            assertTrue(futureGet.isSuccess());
            if(!futureGet.dataMap().values().contains(new Data("hallo2"))) {
              System.err.println("raw data has the value, the evaluated not!");
            }
            assertTrue(futureGet.dataMap().values().contains(new Data("hallo2")));
            assertTrue(futureGet.dataMap().values().size() == 1);

            shutdown();
           
            if(forcedConnectionType == ConnectionType.DIRECT) {
              SeedNodeForTesting.stop();
            }
        }
    }


    // The sendDirect operation fails in port forwarding mode because most routers does not support NAT reflections.
    // 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
    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);

                final CountDownLatch countDownLatch = new CountDownLatch(1);

                final StringBuilder result = new StringBuilder();
                peer2DHT.peer().objectDataReply(new ObjectDataReply() {
                    @Override
                    public Object reply(PeerAddress sender, Object request) throws Exception {
                        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!");

                assertEquals("hallo", result.toString());
                assertTrue(futureDirect.isSuccess());
                log.debug(futureDirect.object().toString());
                assertEquals("pong", futureDirect.object());
            }

            shutdown();
        }
    }

    // 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
    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);

            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();
        }
    }


    ///////////////////////////////////////////////////////////////////////////////////////////
    // 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)) {
            return cachedPeers.get(id);
        }*/
        Peer peer = null;
        try {
          Number160 peerId = Number160.createHash(clientId);
          PeerMapConfiguration pmc = new PeerMapConfiguration(peerId).peerNoVerification();
          PeerMap pm = new PeerMap(pmc);
          ChannelClientConfiguration cc = PeerBuilder.createDefaultChannelClientConfiguration();
          cc.maxPermitsTCP(100);
          cc.maxPermitsUDP(100);
            peer = new PeerBuilder(peerId).channelClientConfiguration(cc).ports(clientPort).peerMap(pm).start();
            PeerAddress masterNodeAddress = new PeerAddress(Number160.createHash(seedNodeId), seedNodeIP, seedNodePort,
                                                            seedNodePort);
            FutureDiscover futureDiscover = peer.discover().peerAddress(masterNodeAddress).start();
            futureDiscover.awaitUninterruptibly();
            if (futureDiscover.isSuccess()) {
                log.info("Discover with direct connection successful. Address = " + futureDiscover.peerAddress());
                //cachedPeers.put(id, peer);
               
                //bootstrap
                FutureBootstrap fb = peer.bootstrap().peerAddress(masterNodeAddress).start();
                fb.awaitUninterruptibly();
                if (fb.isSuccess()) {
                  log.info("Bootstrap with direct connection successful. Address = " + fb.bootstrapTo());
                  return peer;
                } else {
                  return null;
                }
            }
            else {
                log.warn("Discover with direct connection failed. Reason = " + futureDiscover.failedReason());
                peer.shutdown().awaitUninterruptibly();
                return null;
            }
        } catch (IOException e) {
            log.warn("Discover with direct connection failed. Exception = " + e.getMessage());
            if (peer != null)
                peer.shutdown().awaitUninterruptibly();

            e.printStackTrace();
            return null;
        }
    }

    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)) {
            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();
            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.awaitUninterruptibly();
                if (futureDiscover.isSuccess()) {
                    log.info("Discover with automatic port forwarding was successful. Address = " + futureDiscover
                            .peerAddress());
                    //cachedPeers.put(id, peer);
                    return peer;
                }
                else {
                    log.warn("Discover with automatic port forwarding failed. Reason = " + futureDiscover
                            .failedReason());
                    peer.shutdown().awaitUninterruptibly();
                    return null;
                }
            }
            else {
                log.warn("StartSetupPortforwarding failed. Reason = " + futureNAT
                        .failedReason());
                peer.shutdown().awaitUninterruptibly();
                return null;
            }
        } catch (IOException e) {
            log.warn("Discover with automatic port forwarding failed. Exception = " + e.getMessage());
            if (peer != null)
                peer.shutdown().awaitUninterruptibly();

            e.printStackTrace();
            return null;
        }
    }

    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)) {
            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();
            FutureNAT futureNAT = peerNAT.startSetupPortforwarding(futureDiscover);
            FutureRelayNAT futureRelayNAT = peerNAT.startRelay(futureDiscover, futureNAT);
            futureRelayNAT.awaitUninterruptibly();
            if (futureRelayNAT.isSuccess()) {
                log.info("Bootstrap using relay was successful. Address = " + peer.peerAddress());
                //cachedPeers.put(id, peer);
                return peer;

            }
            else {
                log.error("Bootstrap using relay failed " + futureRelayNAT.failedReason());
                futureRelayNAT.shutdown();
                peer.shutdown().awaitUninterruptibly();
                return null;
            }
        } catch (IOException e) {
            log.error("Bootstrap using relay failed. Exception " + e.getMessage());
            if (peer != null)
                peer.shutdown().awaitUninterruptibly();

            e.printStackTrace();
            return null;
        }
    }

    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);
        if (peer != null)
            return peer;

        resolvedConnectionType = ConnectionType.NAT;
        peer = bootstrapWithPortForwarding(clientId, clientPort, seedNodeId, seedNodeIP, seedNodePort);
        if (peer != null)
            return peer;

        resolvedConnectionType = ConnectionType.RELAY;
        peer = bootstrapInRelayMode(clientId, clientPort, seedNodeId, seedNodeIP, seedNodePort);
        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);

        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);
        }
        else if (forcedConnectionType == ConnectionType.NAT) {
            peer = bootstrapWithPortForwarding(clientId, clientPort, seedNodeId, seedNodeIP, seedNodePort);
        }
        else if (forcedConnectionType == ConnectionType.RELAY) {
            peer = bootstrapInRelayMode(clientId, clientPort, seedNodeId, seedNodeIP, seedNodePort);
        }
        else {
            peer = bootstrapInUnknownMode(clientId, clientPort, seedNodeId, seedNodeIP, seedNodePort);
        }

        if (peer == null)
            Assert.fail("Bootstrapping failed. Check if the seed node is running. " +
                                "forcedConnectionType= " + forcedConnectionType +
                                " resolvedConnectionType= " + resolvedConnectionType +
                                " seedNodeId= " + seedNodeId +
                                " seedNodeIP= " + seedNodeIP +
                                " seedNodePort= " + seedNodePort);

        return new PeerBuilderDHT(peer).start();
    }
}
TOP

Related Classes of net.tomp2p.examples.TomP2PTests

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.