package com.kixeye.kixmpp.server; /* * #%L * KIXMPP * %% * Copyright (C) 2014 KIXEYE, Inc * %% * 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 com.kixeye.kixmpp.KixmppJid; import com.kixeye.kixmpp.client.KixmppClient; import com.kixeye.kixmpp.client.module.muc.MucJoin; import com.kixeye.kixmpp.client.module.muc.MucKixmppClientModule; import com.kixeye.kixmpp.client.module.muc.MucListener; import com.kixeye.kixmpp.client.module.muc.MucMessage; import com.kixeye.kixmpp.client.module.presence.Presence; import com.kixeye.kixmpp.client.module.presence.PresenceKixmppClientModule; import com.kixeye.kixmpp.client.module.presence.PresenceListener; import com.kixeye.kixmpp.p2p.ClusterClient; import com.kixeye.kixmpp.p2p.discovery.ConstNodeDiscovery; import com.kixeye.kixmpp.p2p.node.NodeAddress; import com.kixeye.kixmpp.server.module.auth.InMemoryAuthenticationService; import com.kixeye.kixmpp.server.module.auth.SaslKixmppServerModule; import com.kixeye.kixmpp.server.module.muc.MucKixmppServerModule; import com.kixeye.kixmpp.server.utils.SocketUtils; import io.netty.handler.ssl.SslContext; import org.junit.Assert; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.net.ssl.SSLException; import java.net.InetSocketAddress; import java.util.concurrent.ExecutionException; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; public class ClusterTest { public static final InetSocketAddress SERVER_A_SOCKET = new InetSocketAddress(SocketUtils.findAvailableTcpPort()); public static final InetSocketAddress SERVER_B_SOCKET = new InetSocketAddress(SocketUtils.findAvailableTcpPort()); public static final InetSocketAddress SERVER_A_CLUSTER = new InetSocketAddress("127.0.0.1",SocketUtils.findAvailableTcpPort()); public static final InetSocketAddress SERVER_B_CLUSTER = new InetSocketAddress("127.0.0.1",SocketUtils.findAvailableTcpPort()); public static final ConstNodeDiscovery discovery = new ConstNodeDiscovery( new NodeAddress(SERVER_A_CLUSTER.getHostName(), SERVER_A_CLUSTER.getPort()), new NodeAddress(SERVER_B_CLUSTER.getHostName(), SERVER_B_CLUSTER.getPort()) ); @Test public void twoNodeCluster() throws Exception { // turn on Netty's leak detector System.setProperty("io.netty.leakDetectionLevel","PARANOID"); // start servers KixmppServer serverA = new KixmppServer(SERVER_A_SOCKET, "testChat", SERVER_A_CLUSTER, discovery); KixmppServer serverB = new KixmppServer(SERVER_B_SOCKET, "testChat", SERVER_B_CLUSTER, discovery); serverA.start().get(); serverB.start().get(); // start clients TestClient clientA = new TestClient(serverA,"userA"); TestClient clientB = new TestClient(serverB,"userB"); clientA.connect(); clientB.connect(); // spin waiting for cluster waitForCluster(serverA.getCluster()); waitForCluster(serverB.getCluster()); // send message to room clientA.sendRoomMessage(); // verity both clients got the message clientA.verifyRoomMessage(); clientB.verifyRoomMessage(); // shut everything down clientA.disconnect(); clientB.disconnect(); serverA.stop(); serverB.stop(); } private void waitForCluster(ClusterClient cluster) throws InterruptedException { for (int i = 0; ; i++) { if (cluster.getNodeCount() == 2) { break; } if (i > 10) { Assert.fail("cluster failed to form!"); break; } Thread.sleep(500); } } public class TestClient { private final Logger logger = LoggerFactory.getLogger(TestClient.class); private final LinkedBlockingQueue<Presence> presences = new LinkedBlockingQueue<>(); private final LinkedBlockingQueue<MucJoin> mucJoins = new LinkedBlockingQueue<>(); private final LinkedBlockingQueue<MucMessage> mucMessages = new LinkedBlockingQueue<>(); private KixmppServer server; private String username; private KixmppClient client; private MucJoin mucJoin; public TestClient(KixmppServer server, String username) { this.server = server; this.username = username; try { client = new KixmppClient(SslContext.newClientContext(), KixmppClient.Type.TCP); } catch (SSLException e) { logger.error("SSL Exception", e); } } public void connect() throws InterruptedException, ExecutionException, TimeoutException { // create MUC service and room ((InMemoryAuthenticationService) server.module(SaslKixmppServerModule.class).getAuthenticationService()).addUser(username, "testPassword"); server.module(MucKixmppServerModule.class).addService("conference").addRoom("someRoom"); // connect to server client.connect(server.getBindAddress().getHostName(), server.getBindAddress().getPort(), server.getDomain()).get(); // establish message handlers client.module(PresenceKixmppClientModule.class).addPresenceListener(new PresenceListener() { public void handle(Presence presence) { presences.offer(presence); } }); client.module(MucKixmppClientModule.class).addJoinListener(new MucListener<MucJoin>() { public void handle(MucJoin event) { mucJoins.offer(event); } }); client.module(MucKixmppClientModule.class).addMessageListener(new MucListener<MucMessage>() { public void handle(MucMessage event) { mucMessages.offer(event); } }); // login client.login(username, "testPassword", "test").get(2,TimeUnit.SECONDS); // presence to available client.module(PresenceKixmppClientModule.class).updatePresence(new Presence()); Presence presence = presences.poll(2,TimeUnit.SECONDS); Assert.assertNotNull(presence); // join room client.module(MucKixmppClientModule.class).joinRoom(KixmppJid.fromRawJid("someRoom@conference.testChat"), username); mucJoin = mucJoins.poll(5,TimeUnit.SECONDS); Assert.assertNotNull(mucJoin); } public void sendRoomMessage() { client.module(MucKixmppClientModule.class).sendRoomMessage(mucJoin.getRoomJid(), "someMessage", username); } public void verifyRoomMessage() throws InterruptedException { MucMessage message = mucMessages.poll(5, TimeUnit.SECONDS); Assert.assertNotNull(message); } public void disconnect() throws ExecutionException, InterruptedException { client.disconnect().get(); } } }