package network.thunder.core.communication.nio.handler.mid; import io.netty.channel.embedded.EmbeddedChannel; import network.thunder.core.communication.Message; import network.thunder.core.communication.nio.handler.ProcessorHandler; import network.thunder.core.communication.objects.messages.impl.factories.GossipMessageFactoryImpl; import network.thunder.core.communication.objects.messages.impl.message.gossip.GossipGetMessage; import network.thunder.core.communication.objects.messages.impl.message.gossip.GossipInvMessage; import network.thunder.core.communication.objects.messages.impl.message.gossip.GossipSendMessage; import network.thunder.core.communication.objects.messages.impl.message.gossip.objects.P2PDataObject; import network.thunder.core.communication.objects.messages.impl.message.gossip.objects.PubkeyChannelObject; import network.thunder.core.communication.objects.messages.interfaces.factories.ContextFactory; import network.thunder.core.communication.objects.messages.interfaces.factories.GossipMessageFactory; import network.thunder.core.communication.objects.messages.interfaces.helper.LNEventHelper; import network.thunder.core.communication.processor.implementations.gossip.GossipProcessorImpl; import network.thunder.core.communication.processor.interfaces.GossipProcessor; import network.thunder.core.etc.InMemoryDBHandler; import network.thunder.core.etc.MockContextFactory; import network.thunder.core.etc.MockLNEventHelper; import network.thunder.core.mesh.NodeClient; import network.thunder.core.mesh.NodeServer; import org.junit.Before; import org.junit.Test; import java.beans.PropertyVetoException; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Random; import static org.hamcrest.core.IsInstanceOf.instanceOf; import static org.junit.Assert.*; /** * Created by matsjerratsch on 27/10/2015. */ public class GossipHandlerTest { NodeClient node1 = new NodeClient(); NodeClient node2 = new NodeClient(); NodeClient node3 = new NodeClient(); NodeClient node4 = new NodeClient(); NodeServer nodeServer1 = new NodeServer(); NodeServer nodeServer2 = new NodeServer(); NodeServer nodeServer3 = new NodeServer(); NodeServer nodeServer4 = new NodeServer(); InMemoryDBHandler dbHandler1 = new InMemoryDBHandler(); InMemoryDBHandler dbHandler2 = new InMemoryDBHandler(); InMemoryDBHandler dbHandler3 = new InMemoryDBHandler(); InMemoryDBHandler dbHandler4 = new InMemoryDBHandler(); ContextFactory contextFactory1 = new MockContextFactory(nodeServer1, dbHandler1); ContextFactory contextFactory2 = new MockContextFactory(nodeServer2, dbHandler2); ContextFactory contextFactory3 = new MockContextFactory(nodeServer3, dbHandler3); ContextFactory contextFactory4 = new MockContextFactory(nodeServer4, dbHandler4); GossipMessageFactory messageFactory; //Weird naming convention here, because we have channels between two nodes //TODO Refactor GossipProcessor gossipProcessor12; GossipProcessor gossipProcessor21; GossipProcessor gossipProcessor23; GossipProcessor gossipProcessor32; GossipProcessor gossipProcessor34; GossipProcessor gossipProcessor43; EmbeddedChannel channel12; EmbeddedChannel channel21; EmbeddedChannel channel23; EmbeddedChannel channel32; EmbeddedChannel channel34; EmbeddedChannel channel43; LNEventHelper eventHelper = new MockLNEventHelper(); @Before public void prepare () throws PropertyVetoException, SQLException { prepareNodes(); node1.isServer = false; node2.isServer = true; node3.isServer = true; node4.isServer = true; node1.name = "Gossip1"; node2.name = "Gossip2"; node3.name = "Gossip3"; node4.name = "Gossip4"; messageFactory = new GossipMessageFactoryImpl(); messageFactory = new GossipMessageFactoryImpl(); messageFactory = new GossipMessageFactoryImpl(); messageFactory = new GossipMessageFactoryImpl(); gossipProcessor12 = new GossipProcessorImpl(contextFactory1, dbHandler1, node1); gossipProcessor21 = new GossipProcessorImpl(contextFactory2, dbHandler2, node2); gossipProcessor23 = new GossipProcessorImpl(contextFactory2, dbHandler2, node2); gossipProcessor32 = new GossipProcessorImpl(contextFactory3, dbHandler3, node3); gossipProcessor34 = new GossipProcessorImpl(contextFactory3, dbHandler3, node3); gossipProcessor43 = new GossipProcessorImpl(contextFactory4, dbHandler4, node4); channel12 = new EmbeddedChannel(new ProcessorHandler(gossipProcessor12, "Gossip12")); channel21 = new EmbeddedChannel(new ProcessorHandler(gossipProcessor21, "Gossip21")); channel23 = new EmbeddedChannel(new ProcessorHandler(gossipProcessor23, "Gossip23")); channel32 = new EmbeddedChannel(new ProcessorHandler(gossipProcessor32, "Gossip32")); channel34 = new EmbeddedChannel(new ProcessorHandler(gossipProcessor34, "Gossip34")); channel43 = new EmbeddedChannel(new ProcessorHandler(gossipProcessor43, "Gossip43")); clearOutput(); } public void after () { channel12.checkException(); channel21.checkException(); channel21.checkException(); channel23.checkException(); channel32.checkException(); channel34.checkException(); channel43.checkException(); } @Test public void shouldAskForDataAfterInv () throws Exception { ArrayList<byte[]> invList = new ArrayList<>(); for (int i = 0; i < 20; i++) { byte[] b = new byte[20]; new Random().nextBytes(b); invList.add(b); } GossipInvMessage message = messageFactory.getGossipInvMessage(invList); channel12.writeInbound(message); Message message1 = (Message) channel12.readOutbound(); assertThat(message1, instanceOf(GossipGetMessage.class)); GossipGetMessage getMessage = (GossipGetMessage) message1; for (int i = 0; i < invList.size(); i++) { assertTrue(Arrays.equals(getMessage.inventoryList.get(i), invList.get(i))); } after(); } @Test public void shouldOnlySendDataOnceEnoughObjectsArrived () throws Exception { if (GossipProcessor.OBJECT_AMOUNT_TO_SEND == 0) { //TODO currently we need all gossip objects immediately, will be fixed with RP routing return; } List<P2PDataObject> dataList = new ArrayList<>(); for (int i = 0; i < GossipProcessor.OBJECT_AMOUNT_TO_SEND + 1; i++) { dataList.add(PubkeyChannelObject.getRandomObject()); } List<P2PDataObject> dataList1 = dataList.subList(0, GossipProcessor.OBJECT_AMOUNT_TO_SEND - 10); channel21.writeInbound(messageFactory.getGossipSendMessage(dataList1)); assertNull(channel23.readOutbound()); channel21.writeInbound(messageFactory.getGossipSendMessage(dataList)); GossipInvMessage invMessage = (GossipInvMessage) channel23.readOutbound(); assertNotNull(invMessage); assertTrue(invMessage.inventoryList.size() == dataList.size()); after(); } @Test public void shouldSendDataToNextPeer () throws Exception { List<P2PDataObject> dataList = new ArrayList<>(); for (int i = 0; i < GossipProcessor.OBJECT_AMOUNT_TO_SEND + 100; i++) { dataList.add(PubkeyChannelObject.getRandomObject()); } GossipSendMessage sendDataObject = messageFactory.getGossipSendMessage(dataList); channel21.writeInbound(sendDataObject); channel32.writeInbound(channel23.readOutbound()); channel23.writeInbound(channel32.readOutbound()); channel32.writeInbound(channel23.readOutbound()); channel43.writeInbound(channel34.readOutbound()); channel34.writeInbound(channel43.readOutbound()); channel43.writeInbound(channel34.readOutbound()); assertTrue(dbHandler2.totalList.containsAll(dataList)); assertTrue(dbHandler3.totalList.containsAll(dataList)); assertTrue(dbHandler4.totalList.containsAll(dataList)); after(); } private void clearOutput () { channel12.readOutbound(); channel21.readOutbound(); channel23.readOutbound(); channel32.readOutbound(); channel34.readOutbound(); channel43.readOutbound(); } public boolean checkListsEqual (List list1, List list2) { return list1.containsAll(list2) && list2.containsAll(list1); } private void prepareNodes () { prepareNode(nodeServer1); prepareNode(nodeServer2); prepareNode(nodeServer3); prepareNode(nodeServer4); } private void prepareNode (NodeServer node) { node.init(); node.portServer = new Random().nextInt(65555); node.hostServer = "localhost"; } }