package org.gameoss.gridcast.p2p.node;
/*
* #%L
* Gridcast
* %%
* Copyright (C) 2014 Charles Barry
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.gameoss.gridcast.p2p.ClusterClient;
import org.gameoss.gridcast.p2p.discovery.ConstNodeDiscovery;
import org.gameoss.gridcast.p2p.listener.ClusterListener;
import org.gameoss.gridcast.p2p.message.JoinRequest;
import org.gameoss.gridcast.p2p.message.JoinResponse;
import org.gameoss.gridcast.p2p.message.MessageRegistry;
import org.gameoss.gridcast.p2p.message.PingRequest;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.nio.NioEventLoopGroup;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Set;
import java.util.concurrent.*;
@RunWith(JUnit4.class)
public class NodeServerTest {
private final Logger logger = LoggerFactory.getLogger(NodeServerTest.class);
@Test(expected = java.net.BindException.class)
public void portAlreadyInUseTest() {
final MessageRegistry messageRegistry = new MessageRegistry();
final NioEventLoopGroup bossGroup = new NioEventLoopGroup();
final NioEventLoopGroup workerGroup = new NioEventLoopGroup();
NodeServer serverA = new NodeServer();
NodeServer serverB = new NodeServer();
try {
serverA.initialize("127.0.0.1", 8042, bossGroup, workerGroup, messageRegistry, new ChannelInboundHandlerAdapter() );
serverB.initialize("127.0.0.1", 8042, bossGroup, workerGroup, messageRegistry, new ChannelInboundHandlerAdapter() );
} finally {
serverA.shutdown();
serverB.shutdown();
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
@Test
public void clientSendAndServerReceiveTest() throws InterruptedException {
final MessageRegistry messageRegistry = new MessageRegistry();
final NioEventLoopGroup bossGroup = new NioEventLoopGroup();
final NioEventLoopGroup workerGroup = new NioEventLoopGroup();
final BlockingQueue<Object> serverMessages = new LinkedBlockingQueue<>();
final NodeAddress address = new NodeAddress("a",8001);
NodeServer server = new NodeServer();
server.initialize("127.0.0.1",8042, bossGroup, workerGroup, messageRegistry, new ChannelInboundHandlerAdapter(){
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
serverMessages.offer(msg);
}
});
NodeClient client = new NodeClient();
client.initialize("127.0.0.1", 8042, workerGroup, messageRegistry, new ChannelInboundHandlerAdapter());
client.send( new JoinRequest(new NodeId(42), address) );
client.send( new JoinResponse(JoinResponse.ResponseCode.OK,new NodeId(42), address) );
Object msg = serverMessages.poll(5, TimeUnit.SECONDS);
Assert.assertNotNull(msg);
Assert.assertEquals(msg.getClass(), JoinRequest.class);
Assert.assertEquals(((JoinRequest)msg).getJoinerId(), new NodeId(42));
Assert.assertEquals(((JoinRequest)msg).getJoinerAddress(), address);
msg = serverMessages.poll(5, TimeUnit.SECONDS);
Assert.assertNotNull(msg);
Assert.assertEquals(msg.getClass(), JoinResponse.class);
Assert.assertEquals(((JoinResponse)msg).getResult(), JoinResponse.ResponseCode.OK);
client.shutdown();
server.shutdown();
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
@Test
public void peerConnectTest() throws InterruptedException {
final String localhost = "127.0.0.1";
final ConstNodeDiscovery discovery = new ConstNodeDiscovery(
new NodeAddress(localhost,8000),
new NodeAddress(localhost,8001),
new NodeAddress(localhost,8002));
final JoinCountClusterListener listenerA = new JoinCountClusterListener();
final JoinCountClusterListener listenerB = new JoinCountClusterListener();
final JoinCountClusterListener listenerC = new JoinCountClusterListener();
final ClusterClient repA = new ClusterClient(listenerA,localhost, 8000, discovery, 2000, Executors.newSingleThreadScheduledExecutor());
final ClusterClient repB = new ClusterClient(listenerB,localhost, 8001, discovery, 2000, Executors.newSingleThreadScheduledExecutor());
final ClusterClient repC = new ClusterClient(listenerC,localhost, 8002, discovery, 2000, Executors.newSingleThreadScheduledExecutor());
try {
// spin until 3 nodes are found
for (int i = 0; i < 10; i++) {
Thread.sleep(500);
if (repA.getNodeCount() >= 3
&& repB.getNodeCount() >= 3
&& repC.getNodeCount() >= 3) {
break;
}
}
Assert.assertEquals(3, repA.getNodeCount());
Assert.assertEquals(3, repB.getNodeCount());
Assert.assertEquals(3, repC.getNodeCount());
// spin until 3 nodes are process in the callback
for (int i = 0; i < 10; i++) {
Thread.sleep(500);
if (listenerA.getJoinCount() == 3
&& listenerB.getJoinCount() == 3
&& listenerC.getJoinCount() == 3) {
break;
}
}
Assert.assertEquals(3, listenerA.getJoinCount());
Assert.assertEquals(3, listenerB.getJoinCount());
Assert.assertEquals(3, listenerC.getJoinCount());
// send message to all nodes
for (NodeId nid : listenerA.getNodes()) {
repA.sendMessage(nid, new PingRequest());
}
} finally {
repA.shutdown();
repB.shutdown();
repC.shutdown();
}
}
private class JoinCountClusterListener implements ClusterListener {
private final Logger logger = LoggerFactory.getLogger(JoinCountClusterListener.class);
private final ConcurrentSkipListSet<NodeId> nodes = new ConcurrentSkipListSet<>();
@Override
public void onNodeJoin(ClusterClient cluster, NodeId nodeId) {
nodes.add(nodeId);
}
@Override
public void onNodeLeft(ClusterClient cluster, NodeId nodeId) {
nodes.remove(nodeId);
}
@Override
public void onMessage(ClusterClient cluster, NodeId senderId, Object message) {
logger.debug("got a message");
}
public int getJoinCount() {
return nodes.size();
}
public Set<NodeId> getNodes() {
return nodes;
}
}
}