/** * Copyright 2014 Comcast Cable Communications Management, LLC * * 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. */ package com.comcast.viper.flume2storm.connection; import java.io.IOException; import java.util.ArrayList; import java.util.List; import junit.framework.Assert; import org.apache.commons.lang.RandomStringUtils; import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.comcast.viper.flume2storm.connection.parameters.KryoNetConnectionParameters; import com.comcast.viper.flume2storm.connection.receptor.EventReceptorListener; import com.comcast.viper.flume2storm.connection.receptor.EventReceptorStats; import com.comcast.viper.flume2storm.connection.receptor.KryoNetEventReceptor; import com.comcast.viper.flume2storm.connection.sender.EventSenderStats; import com.comcast.viper.flume2storm.connection.sender.EventSenderTestUtils; import com.comcast.viper.flume2storm.connection.sender.KryoNetEventSender; import com.comcast.viper.flume2storm.event.F2SEvent; import com.comcast.viper.flume2storm.event.F2SEventBuilder; import com.comcast.viper.flume2storm.event.F2SEventFactory; import com.comcast.viper.flume2storm.utility.forwarder.TCPForwarder; import com.comcast.viper.flume2storm.utility.forwarder.TCPForwarderBuilder; import com.comcast.viper.flume2storm.utility.test.TestCondition; import com.comcast.viper.flume2storm.utility.test.TestUtils; import com.google.common.collect.ImmutableList; public class KryoNetIntegrationTest { private static final Logger LOG = LoggerFactory.getLogger(KryoNetIntegrationTest.class); protected static final int TEST_TO = 1000; protected static final int RECONNECTION_TO = 1000; protected static KryoNetConnectionParameters connectionParameters; protected static KryoNetParameters kryoNetParameters; protected KryoNetEventSender sender; protected EventSenderStats senderStats; protected EventReceptorStats receptorStats; @BeforeClass public static void init() { connectionParameters = new KryoNetConnectionParameters(); connectionParameters.setObjectBufferSize(1024); connectionParameters.setWriteBufferSize(5120); connectionParameters.setAddress("localhost"); connectionParameters.setServerPort(TestUtils.getAvailablePort()); kryoNetParameters = new KryoNetParameters(); kryoNetParameters.setConnectionTimeout(RECONNECTION_TO); kryoNetParameters.setTerminationTimeout(3000); kryoNetParameters.setRetrySleepDelay(RECONNECTION_TO); } @Before public void setup() throws Exception { sender = new KryoNetEventSender(connectionParameters, kryoNetParameters); sender.getStats().reset(); sender.start(); senderStats = new EventSenderStats(connectionParameters.getId()); receptorStats = new EventReceptorStats(connectionParameters.getId()); } @After public void teardown() throws IOException, InterruptedException { sender.stop(); KryoNetTestUtil.waitSenderShutdown(sender, TEST_TO); } protected List<F2SEvent> generateRandomEvents(int nb) { List<F2SEvent> result = new ArrayList<F2SEvent>(nb); for (int i = 0; i < nb; i++) { result.add(F2SEventFactory.getInstance().createRandomWithHeaders()); } return result; } @Test public void testClientReconnection() throws Exception { // Starting client KryoNetEventReceptor receptor = new KryoNetEventReceptor(connectionParameters, kryoNetParameters); receptor.start(); KryoNetTestUtil.waitReceptorConnected(receptor, TEST_TO); KryoNetTestUtil.checkSenderStatus(sender, senderStats.incrClients()); KryoNetTestUtil.checkReceptorStatus(receptor, receptorStats.setConnected()); // Sending the events final F2SEvent e1 = F2SEventFactory.getInstance().createRandomWithHeaders(); final F2SEvent e2 = F2SEventFactory.getInstance().createRandomWithHeaders(); final F2SEvent e3 = F2SEventFactory.getInstance().createRandomWithHeaders(); sender.send(ImmutableList.of(e1, e2, e3)); // Waiting that all the events have been sent KryoNetTestUtil.checkSenderStatus(sender, senderStats.incrEventsIn(3).incrEventsOut(3)); KryoNetTestUtil.checkReceptorStatus(receptor, receptorStats.incrEventsIn(3).incrEventsQueued(3)); List<F2SEvent> events = receptor.getEvents(); Assert.assertEquals(3, events.size()); Assert.assertEquals(e1, events.get(0)); Assert.assertEquals(e2, events.get(1)); Assert.assertEquals(e3, events.get(2)); KryoNetTestUtil.checkSenderStatus(sender, senderStats); KryoNetTestUtil.checkReceptorStatus(receptor, receptorStats.setEventsQueued(0)); // Disconnecting client receptor.stop(); EventSenderTestUtils.waitNoReceptor(sender, TEST_TO); KryoNetTestUtil.checkSenderStatus(sender, senderStats.decrClients()); KryoNetTestUtil.checkReceptorStatus(receptor, receptorStats.setDisconnected()); // Sending some more events - queued up Assert.assertEquals(0, sender.send(generateRandomEvents(2))); KryoNetTestUtil.checkReceptorStatus(receptor, receptorStats); // Re-connecting client receptor.start(); KryoNetTestUtil.waitReceptorConnected(receptor, TEST_TO); Assert.assertEquals(2, sender.send(generateRandomEvents(2))); KryoNetTestUtil.checkSenderStatus(sender, senderStats.incrClients().incrEventsIn(2).incrEventsOut(2)); KryoNetTestUtil.checkReceptorStatus(receptor, receptorStats.reset().setConnected().incrEventsIn(2) .incrEventsQueued(2)); Assert.assertEquals(2, receptor.getEvents().size()); KryoNetTestUtil.checkSenderStatus(sender, senderStats); KryoNetTestUtil.checkReceptorStatus(receptor, receptorStats.setEventsQueued(0)); // Disconnecting client receptor.stop(); } /** * Testing sending an event that is larger than the object buffer size. When * doing so, the sender sends it successfully, but the receptor will generate * an exception and then disconnect. The {@link KryoNetEventReceptor} * implementation will reconnect right away. * * @throws Exception */ @Test public void testMessageTooBig() throws Exception { final byte[] prettyBig = new byte[connectionParameters.getObjectBufferSize() + 512]; for (int i = 0; i < prettyBig.length; i++) { final int mod = i % 10; prettyBig[i] = mod == 9 ? (byte) '-' : (byte) ('1' + mod); } final F2SEvent e1 = new F2SEventBuilder().body(prettyBig).get(); KryoNetEventReceptor receptor = new KryoNetEventReceptor(connectionParameters, kryoNetParameters); receptor.start(); KryoNetTestUtil.waitReceptorConnected(receptor, TEST_TO); KryoNetTestUtil.checkSenderStatus(sender, senderStats.incrClients()); KryoNetTestUtil.checkReceptorStatus(receptor, receptorStats.setConnected()); Assert.assertEquals(1, sender.send(ImmutableList.of(e1))); // Reconnect should be immediate, but the nb of received messages won't incr KryoNetTestUtil.waitReceptorConnected(receptor, RECONNECTION_TO + TEST_TO); KryoNetTestUtil.checkSenderStatus(sender, senderStats.incrEventsIn().incrEventsOut()); KryoNetTestUtil.checkReceptorStatus(receptor, receptorStats); final F2SEvent e2 = F2SEventFactory.getInstance().createRandomWithHeaders(); Assert.assertEquals(1, sender.send(ImmutableList.of(e2))); KryoNetTestUtil.waitReceptorQueuedAtLeast(receptor, 1, TEST_TO); List<F2SEvent> receivedEvents = receptor.getEvents(); Assert.assertEquals(1, receivedEvents.size()); Assert.assertEquals(e2, receivedEvents.get(0)); KryoNetTestUtil.checkSenderStatus(sender, senderStats.incrEventsIn().incrEventsOut()); KryoNetTestUtil.checkReceptorStatus(receptor, receptorStats.incrEventsIn()); receptor.stop(); EventSenderTestUtils.waitNoReceptor(sender, TEST_TO); } /** * Test that the buffer underflow exception is not thrown * * @throws Exception * If anything went wrong */ @Test public void testBufferUnderflow() throws Exception { int fairlyBig = 512 + 20; final byte[] prettyBig = new byte[fairlyBig]; for (int i = 0; i < prettyBig.length; i++) { final int mod = i % 10; prettyBig[i] = mod == 9 ? (byte) '-' : (byte) ('1' + mod); } final F2SEvent e1 = new F2SEventBuilder().body(prettyBig).get(); Assert.assertTrue(fairlyBig > 512 && fairlyBig < connectionParameters.getObjectBufferSize()); KryoNetEventReceptor receptor = new KryoNetEventReceptor(connectionParameters, kryoNetParameters); receptor.start(); KryoNetTestUtil.waitReceptorConnected(receptor, TEST_TO); KryoNetTestUtil.checkSenderStatus(sender, senderStats.incrClients()); KryoNetTestUtil.checkReceptorStatus(receptor, receptorStats.setConnected()); Assert.assertEquals(1, sender.send(ImmutableList.of(e1))); KryoNetTestUtil.checkSenderStatus(sender, senderStats.incrEventsIn().incrEventsOut()); KryoNetTestUtil.checkReceptorStatus(receptor, receptorStats.incrEventsIn().incrEventsQueued()); receptor.stop(); EventSenderTestUtils.waitNoReceptor(sender, TEST_TO); } @Test public void testServerRestart() throws Exception { // Starting client KryoNetEventReceptor receptor = new KryoNetEventReceptor(connectionParameters, kryoNetParameters); receptor.start(); KryoNetTestUtil.waitReceptorConnected(receptor, TEST_TO); KryoNetTestUtil.checkSenderStatus(sender, senderStats.incrClients()); KryoNetTestUtil.checkReceptorStatus(receptor, receptorStats.setConnected()); // Sending the events Assert.assertEquals(3, sender.send(generateRandomEvents(3))); KryoNetTestUtil.checkSenderStatus(sender, senderStats.incrEventsIn(3).incrEventsOut(3)); KryoNetTestUtil.checkReceptorStatus(receptor, receptorStats.incrEventsIn(3).incrEventsQueued(3)); Assert.assertEquals(3, receptor.getEvents().size()); KryoNetTestUtil.checkSenderStatus(sender, senderStats); KryoNetTestUtil.checkReceptorStatus(receptor, receptorStats.setEventsQueued(0)); // Stopping server sender.stop(); KryoNetTestUtil.waitSenderShutdown(sender, TEST_TO); Thread.sleep(4000); KryoNetTestUtil.checkSenderStatus(sender, senderStats.decrClients()); KryoNetTestUtil.checkReceptorStatus(receptor, receptorStats.setDisconnected()); // Sending some more events Assert.assertEquals(0, sender.send(generateRandomEvents(3))); // Starting server sender.getStats().reset(); sender.start(); KryoNetTestUtil.waitReceptorConnected(receptor, RECONNECTION_TO + TEST_TO); Assert.assertEquals(5, sender.send(generateRandomEvents(5))); KryoNetTestUtil.checkSenderStatus(sender, senderStats.reset().incrClients().incrEventsIn(5).incrEventsOut(5)); KryoNetTestUtil.checkReceptorStatus(receptor, receptorStats.setConnected().incrEventsIn(5).incrEventsQueued(5)); Assert.assertEquals(5, receptor.getEvents().size()); KryoNetTestUtil.checkSenderStatus(sender, senderStats); KryoNetTestUtil.checkReceptorStatus(receptor, receptorStats.setEventsQueued(0)); // Disconnecting client receptor.stop(); } @Test public void testBadConnection() throws Exception { // Setting up proxy final String proxyHost = "127.0.0.1"; final int proxyPort = TestUtils.getAvailablePort(); final TCPForwarderBuilder tcpForwarderBuilder = new TCPForwarderBuilder(); tcpForwarderBuilder.setListenAddress(proxyHost).setInputPort(proxyPort) .setOutputServer(connectionParameters.getAddress()).setOutputPort(connectionParameters.getPort()); final TCPForwarder forwarder = tcpForwarderBuilder.build(); forwarder.start(); TestUtils.waitFor(new TestCondition() { @Override public boolean evaluate() { return forwarder.isActive(); } }, TEST_TO); // Starting client connectionParameters.setServerPort(proxyPort); KryoNetEventReceptor receptor = new KryoNetEventReceptor(connectionParameters, kryoNetParameters); receptor.start(); KryoNetTestUtil.waitReceptorConnected(receptor, TEST_TO); KryoNetTestUtil.checkSenderStatus(sender, senderStats.incrClients()); KryoNetTestUtil.checkReceptorStatus(receptor, receptorStats.setConnected()); // Sending the events Assert.assertEquals(3, sender.send(generateRandomEvents(3))); KryoNetTestUtil.checkSenderStatus(sender, senderStats.incrEventsIn(3).incrEventsOut(3)); KryoNetTestUtil.checkReceptorStatus(receptor, receptorStats.incrEventsIn(3).incrEventsQueued(3)); Assert.assertEquals(3, receptor.getEvents().size()); KryoNetTestUtil.checkSenderStatus(sender, senderStats); KryoNetTestUtil.checkReceptorStatus(receptor, receptorStats.setEventsQueued(0)); // Screwing up with the connection (short amount of time) forwarder.freeze(); Thread.sleep(RECONNECTION_TO / 2); // Sending some more events Assert.assertEquals(2, sender.send(generateRandomEvents(2))); KryoNetTestUtil.checkSenderStatus(sender, senderStats.incrEventsIn(2).incrEventsOut(2)); KryoNetTestUtil.checkReceptorStatus(receptor, receptorStats); // Re-establishing connection forwarder.resume(); KryoNetTestUtil.checkReceptorStatus(receptor, receptorStats.incrEventsIn(2).incrEventsQueued(2)); Assert.assertEquals(2, receptor.getEvents().size()); KryoNetTestUtil.checkSenderStatus(sender, senderStats); KryoNetTestUtil.checkReceptorStatus(receptor, receptorStats.setEventsQueued(0)); // Screwing up with the connection some more forwarder.stop(); EventSenderTestUtils.waitNoReceptor(sender, TEST_TO); Assert.assertEquals(0, sender.send(generateRandomEvents(2))); KryoNetTestUtil.checkSenderStatus(sender, senderStats.decrClients()); KryoNetTestUtil.checkReceptorStatus(receptor, receptorStats.setDisconnected()); Thread.sleep(TEST_TO); // Re-establishing connection forwarder.start(); KryoNetTestUtil.waitReceptorConnected(receptor, TEST_TO); Assert.assertEquals(2, sender.send(generateRandomEvents(2))); KryoNetTestUtil.waitReceptorQueuedAtLeast(receptor, 2, TEST_TO); KryoNetTestUtil.checkSenderStatus(sender, senderStats.incrClients().incrEventsIn(2).incrEventsOut(2)); KryoNetTestUtil.checkReceptorStatus(receptor, receptorStats.setConnected().incrEventsIn(2).incrEventsQueued(2)); Assert.assertEquals(2, receptor.getEvents().size()); KryoNetTestUtil.checkSenderStatus(sender, senderStats); KryoNetTestUtil.checkReceptorStatus(receptor, receptorStats.setEventsQueued(0)); // Disconnecting client receptor.stop(); forwarder.stop(); } @Test public void testPerformance() throws Exception { final int testSize = 1000; final KryoNetEventReceptor receptor = new KryoNetEventReceptor(connectionParameters, kryoNetParameters); receptor.addListener(new EventReceptorListener() { @Override public void onEvent(List<F2SEvent> events) { try { Thread.sleep(1); } catch (InterruptedException e) { } } @Override public void onDisconnection() { } @Override public void onConnection() { } }); // Creating test event final ImmutableList<F2SEvent> toSend = ImmutableList.of(F2SEventFactory.getInstance().create( RandomStringUtils.random(256))); Thread senderThread = new Thread() { @Override public void run() { try { LOG.info("Sender: thread started"); KryoNetTestUtil.waitReceptorConnected(receptor, TEST_TO); LOG.info("Sender: connected receptor"); for (int i = 1; i <= testSize; i++) { while (sender.send(toSend) == 0) { Thread.sleep(100); } if (i % 100 == 0) LOG.debug("Sender: Sent " + i + " messages"); } LOG.info("Sender: thread terminated"); } catch (InterruptedException e) { e.printStackTrace(); } } }; Thread receptorThread = new Thread() { @Override public void run() { try { LOG.info("Receptor: thread started"); receptor.start(); KryoNetTestUtil.waitReceptorConnected(receptor, TEST_TO); LOG.info("Receptor: connected to sender"); int nbMsgReceived = 0; while (nbMsgReceived < testSize) { List<F2SEvent> events = receptor.getEvents(); nbMsgReceived += events.size(); LOG.debug("Receptor: Received " + nbMsgReceived + " messages"); Thread.sleep(100); } receptor.stop(); LOG.info("Receptor: thread terminated"); } catch (InterruptedException e) { e.printStackTrace(); } } }; senderThread.start(); receptorThread.start(); senderThread.join(); receptorThread.join(); } }