/* * The MIT License * * Copyright 2014 sorrge. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package org.nyan.dch.communication.transport.simulator; import com.google.common.collect.Sets; import java.util.ArrayList; import java.util.Date; import java.util.Random; import java.util.Set; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.Logger; import org.junit.Test; import static org.junit.Assert.*; import org.nyan.dch.communication.Connections; import org.nyan.dch.communication.IAddress; import org.nyan.dch.communication.ProtocolException; import org.nyan.dch.communication.RemoteNodeMessages; import org.nyan.dch.crypto.SHA256Hash; import org.nyan.dch.node.Node; import org.nyan.dch.posts.Post; import org.nyan.dch.posts.PostData; import org.nyan.dch.posts.Storage; import org.nyan.dch.posts.StorageTest; import org.nyan.dch.posts.Thread; /** * * @author sorrge */ public class NetworkTest { public NetworkTest() { Logger root = Logger.getLogger(""); root.setLevel(Level.WARNING); Handler[] handlers = root.getHandlers(); for(Handler h: handlers) h.setLevel(Level.WARNING); } /** * Test of class Network. */ @Test public void testAddNode() throws ProtocolException { Random rand = new Random(12); Network net = new Network(rand); String[] boards = new String[] { "b", "e", "d" }; Node n1 = new Node(new Storage(boards)), n2 = new Node(new Storage(boards)); net.AddNode(n1); net.AddNode(n2); assert(net.StepN(100)); ArrayList<IAddress> addrs = new ArrayList<>(net.GetAddresses()); assert(net.GetConnection(addrs.get(0)).GetConnectedHost(addrs.get(1)) != null); assert(net.GetConnection(addrs.get(1)).GetConnectedHost(addrs.get(0)) != null); assert(n1.Connections().size() == 1); assert(n2.Connections().size() == 1); Post p = new Post(new PostData("b", null, String.valueOf(rand.nextInt()), String.valueOf(rand.nextInt()), new Date())); n1.AddLocalPost(p); assert(net.StepN(100)); assert(n2.storage.Contains(p)); net.RemoveHost(addrs.get(0)); assert(n1.Connections().isEmpty()); assert(n2.Connections().isEmpty()); assert(net.GetConnection(addrs.get(0)) == null); assert(net.GetConnection(addrs.get(1)).GetConnectedHost(addrs.get(0)) == null); } /** * Test of class Network. */ @Test public void testMoreNodes() throws ProtocolException { Random rand = new Random(12); Network net = new Network(rand); String[] boards = new String[] { "b", "e", "d" }; int numNodes = 100; for(int i = 0; i < numNodes; ++i) net.AddNode(new Node(new Storage(boards))); assert(net.StepN(100 * numNodes)); ArrayList<Node> allNodes = new ArrayList<>(numNodes); for(NetworkConnection nc : net.GetHosts()) { assert(nc.Connections().size() >= Connections.WantConnections); assert(nc.Connections().size() == ((Node)((Connections)nc.GetConnections()).node).Connections().size()); for(HostConnection hc : nc.Connections()) assert(net.GetConnection(hc.GetAddress()).Connections().contains(hc.GetRemoteHost())); allNodes.add((Node)((Connections)nc.GetConnections()).node); } assert(allNodes.size() == numNodes); Post p = new Post(new PostData("b", null, String.valueOf(rand.nextInt()), String.valueOf(rand.nextInt()), new Date())); allNodes.get(rand.nextInt(numNodes)).AddLocalPost(p); assert(net.StepN(100 * numNodes)); for(Node n : allNodes) assert(n.storage.Contains(p)); } /** * Test of class Network. */ @Test public void testThreadProp() throws ProtocolException { assert(Thread.MaxPosts > 0); Random rand = new Random(12); Network net = new Network(rand); String[] boards = new String[] { "b", "e", "d" }; int numNodes = 100, numPosts = Thread.MaxPosts * 2; for(int i = 0; i < numNodes; ++i) net.AddNode(new Node(new Storage(boards))); assert(net.StepN(100 * numNodes)); ArrayList<Node> allNodes = new ArrayList<>(numNodes); for(NetworkConnection nc : net.GetHosts()) allNodes.add((Node)((Connections)nc.GetConnections()).node); assert(allNodes.size() == numNodes); ArrayList<Post> thread = StorageTest.GenerateThread(numPosts, rand, "b", 111); for(Post p : thread) { allNodes.get(rand.nextInt(numNodes)).AddLocalPost(p); assert(net.StepN(100 * numNodes)); } for(Node n : allNodes) for(Post p : thread) assert(n.storage.Contains(p)); } /** * Test of class Network. */ @Test public void testSync() throws ProtocolException { Random rand = new Random(123); Network net = new Network(rand); String[] boards = new String[] { "b", "e", "d" }; int numNodes = 70, numPosts = 5000; for(int i = 0; i < numNodes; ++i) net.AddNode(new Node(new Storage(boards))); assert(net.StepN(100 * numNodes)); ArrayList<Node> allNodes = new ArrayList<>(numNodes + 1); ArrayList<IAddress> addresses = new ArrayList<>(numNodes + 1); for(IAddress addr : net.GetAddresses()) { allNodes.add((Node)((Connections)net.GetConnection(addr).GetConnections()).node); addresses.add(addr); } assert(allNodes.size() == numNodes); ArrayList<Post> posts = StorageTest.GenerateStream(numPosts, rand, 111, "b", "e", "d"); for(Post p : posts) { allNodes.get(rand.nextInt(numNodes)).AddLocalPost(p); assert(net.StepN(100 * numNodes)); } for(int i = 1; i < numNodes; ++i) StorageTest.AssertSynced(allNodes.get(0).storage, allNodes.get(i).storage); Node newNode = new Node(new Storage(boards)); IAddress newAddr = net.AddNode(newNode); assert(net.StepN(100 * numNodes)); StorageTest.AssertSynced(newNode.storage, allNodes.get(0).storage); allNodes.add(newNode); addresses.add(newAddr); IAddress toDelete = addresses.get(rand.nextInt(numNodes)); Node disconnected = (Node)((Connections)net.GetConnection(toDelete).GetConnections()).node; net.RemoveHost(toDelete); for(NetworkConnection nc : net.GetHosts()) for(HostConnection hc : nc.Connections()) assert(((Connections)((RemoteNodeMessages)hc.GetRemoteHost().GetMyNode()).connections).node != disconnected); posts = StorageTest.GenerateStream(numPosts, rand, 1110000, "b", "e", "d"); for(Post p : posts) { Node n = allNodes.get(rand.nextInt(numNodes)); if(n != disconnected) n.AddLocalPost(p); assert(net.StepN(100 * numNodes)); } Node oldNode = allNodes.get(0); if(oldNode == disconnected) oldNode = allNodes.get(1); Set<SHA256Hash> postsOnBoard1 = StorageTest.GatherPosts(disconnected.storage), postsOnBoard2 = StorageTest.GatherPosts(oldNode.storage); assert(!postsOnBoard1.equals(postsOnBoard2)); for(Node n : allNodes) System.out.printf("Node %s has %d posts\n", n, StorageTest.GatherPosts(n.storage).size()); System.out.printf("Reconnecting node %s\n", disconnected.toString()); net.AddNode(disconnected); assert(net.StepN(numPosts * 100)); for(Node n : allNodes) System.out.printf("Node %s has %d posts\n", n, StorageTest.GatherPosts(n.storage).size()); Set<SHA256Hash> missing = Sets.difference(StorageTest.GatherPosts(oldNode.storage), StorageTest.GatherPosts(disconnected.storage)); for(SHA256Hash s : missing) { Post p = oldNode.storage.GetPost(s); System.out.printf("Post %s missing, thread: %s\n", s, p.GetThreadId()); } for(NetworkConnection nc : net.GetHosts()) { assert(nc.Connections().size() >= Math.min(Connections.WantConnections, numNodes)); assert(nc.Connections().size() == ((Node)((Connections)nc.GetConnections()).node).Connections().size()); for(HostConnection hc : nc.Connections()) assert(net.GetConnection(hc.GetAddress()).Connections().contains(hc.GetRemoteHost())); } StorageTest.AssertSynced(disconnected.storage, oldNode.storage); } /** * Test synchronization of a split thread */ @Test public void testSyncThread() throws ProtocolException { final int numPosts = 10; Random rand = new Random(12); String[] boards = new String[] { "b", "e", "d" }; Network net = new Network(rand); Node n1 = new Node(new Storage(boards)); Node n2 = new Node(new Storage(boards)); net.AddNode(n1); assert(net.StepN(numPosts * 100)); ArrayList<Post> allPosts = StorageTest.GenerateThread(numPosts, rand, "b", 111); n1.AddLocalPost(allPosts.get(0)); for(int i = 1; i < numPosts; ++i) { n2.AddLocalPost(allPosts.get(i)); assert(net.StepN(numPosts * 100)); } Set<SHA256Hash> postsOnBoard1 = StorageTest.GatherPosts(n1.storage), postsOnBoard2 = StorageTest.GatherPosts(n2.storage); assert(!postsOnBoard1.equals(postsOnBoard2)); System.out.printf("Node %s has %d posts\n", n1.toString(), StorageTest.GatherPosts(n1.storage).size()); System.out.printf("Node %s has %d posts\n", n2.toString(), StorageTest.GatherPosts(n2.storage).size()); net.AddNode(n2); assert(net.StepN(numPosts * 100)); StorageTest.AssertSynced(n1.storage, n2.storage); } /** * Test of class Network. Syncing after some kind of network split */ @Test public void testSyncApprox() throws ProtocolException { Random rand = new Random(123); Network net = new Network(rand); String[] boards = new String[] { "b", "e", "d" }; int numNodes = 70, numPosts = 5000; for(int i = 0; i < numNodes; ++i) net.AddNode(new Node(new Storage(boards))); assert(net.StepN(100 * numNodes)); ArrayList<Node> allNodes = new ArrayList<>(numNodes + 1); ArrayList<IAddress> addresses = new ArrayList<>(numNodes + 1); for(IAddress addr : net.GetAddresses()) { allNodes.add((Node)((Connections)net.GetConnection(addr).GetConnections()).node); addresses.add(addr); } assert(allNodes.size() == numNodes); ArrayList<Post> posts = StorageTest.GenerateStream(numPosts, rand, 111, "b", "e", "d"); for(Post p : posts) { allNodes.get(rand.nextInt(numNodes)).AddLocalPost(p); assert(net.StepN(100 * numNodes)); } for(int i = 1; i < numNodes; ++i) StorageTest.AssertSynced(allNodes.get(0).storage, allNodes.get(i).storage); Node newNode = new Node(new Storage(boards)); IAddress newAddr = net.AddNode(newNode); assert(net.StepN(100 * numNodes)); StorageTest.AssertSynced(newNode.storage, allNodes.get(0).storage); allNodes.add(newNode); addresses.add(newAddr); IAddress toDelete = addresses.get(rand.nextInt(numNodes)); Node disconnected = (Node)((Connections)net.GetConnection(toDelete).GetConnections()).node; net.RemoveHost(toDelete); for(NetworkConnection nc : net.GetHosts()) for(HostConnection hc : nc.Connections()) assert(((Connections)((RemoteNodeMessages)hc.GetRemoteHost().GetMyNode()).connections).node != disconnected); posts = StorageTest.GenerateStream(numPosts, rand, 1110000, "b", "e", "d"); for(Post p : posts) { Node n = allNodes.get(rand.nextInt(numNodes)); n.AddLocalPost(p); assert(net.StepN(100 * numNodes)); } Node oldNode = allNodes.get(0); if(oldNode == disconnected) oldNode = allNodes.get(1); Set<SHA256Hash> postsOnBoard1 = StorageTest.GatherPosts(disconnected.storage), postsOnBoard2 = StorageTest.GatherPosts(oldNode.storage); assert(!postsOnBoard1.equals(postsOnBoard2)); for(Node n : allNodes) System.out.printf("Node %s has %d posts\n", n, StorageTest.GatherPosts(n.storage).size()); System.out.printf("Reconnecting node %s\n", disconnected.toString()); net.AddNode(disconnected); assert(net.StepN(numPosts * 100)); for(Node n : allNodes) System.out.printf("Node %s has %d posts\n", n, StorageTest.GatherPosts(n.storage).size()); Set<SHA256Hash> missing = Sets.difference(StorageTest.GatherPosts(oldNode.storage), StorageTest.GatherPosts(disconnected.storage)); for(SHA256Hash s : missing) { Post p = oldNode.storage.GetPost(s); System.out.printf("Post %s missing, thread: %s\n", s, p.GetThreadId()); } for(NetworkConnection nc : net.GetHosts()) { assert(nc.Connections().size() >= Math.min(Connections.WantConnections, numNodes)); assert(nc.Connections().size() == ((Node)((Connections)nc.GetConnections()).node).Connections().size()); for(HostConnection hc : nc.Connections()) assert(net.GetConnection(hc.GetAddress()).Connections().contains(hc.GetRemoteHost())); } StorageTest.AssertApproxSynced(disconnected.storage, oldNode.storage, 0.9); } /** * Test of class Network. */ @Test public void testMoreNodesNAT() throws ProtocolException { Random rand = new Random(12); Network net = new Network(rand); String[] boards = new String[] { "b", "e", "d" }; int numNodes = 300; for(int i = 0; i < numNodes; ++i) net.AddNode(new Node(new Storage(boards)), rand.nextBoolean()); assert(net.StepN(100 * numNodes)); ArrayList<Node> allNodes = new ArrayList<>(numNodes); for(NetworkConnection nc : net.GetHosts()) { assert(nc.Connections().size() >= Connections.WantConnections); assert(nc.Connections().size() == ((Node)((Connections)nc.GetConnections()).node).Connections().size()); for(HostConnection hc : nc.Connections()) assert(net.GetConnection(hc.GetAddress()).Connections().contains(hc.GetRemoteHost())); allNodes.add((Node)((Connections)nc.GetConnections()).node); assert(!((Acceptance)nc.GetAcceptance()).NeedToConfirmAcceptance()); assert(((Acceptance)nc.GetAcceptance()).CanAcceptConnections() == nc.CanAccept()); } assert(allNodes.size() == numNodes); Post p = new Post(new PostData("b", null, String.valueOf(rand.nextInt()), String.valueOf(rand.nextInt()), new Date())); allNodes.get(rand.nextInt(numNodes)).AddLocalPost(p); assert(net.StepN(100 * numNodes)); for(Node n : allNodes) assert(n.storage.Contains(p)); } }