/*******************************************************************************
* Copyright (c) 2015
*
* 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 jsettlers.network.infrastructure.channel;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.List;
import jsettlers.network.NetworkConstants;
import jsettlers.network.NetworkConstants.ENetworkKey;
import jsettlers.network.TestUtils;
import jsettlers.network.infrastructure.channel.listeners.BufferingPacketListener;
import jsettlers.network.infrastructure.channel.packet.EmptyPacket;
import jsettlers.network.infrastructure.channel.reject.RejectPacket;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* Test for class {@link Channel}.
*
* @author Andreas Eberle
*
*/
public class ChannelTest {
private Channel c1;
private Channel c2;
@Before
public void setUp() throws IOException {
Channel[] channels = TestUtils.setUpLoopbackChannels();
c1 = channels[0];
c2 = channels[1];
}
@After
public void tearDown() {
c1.close();
c2.close();
}
@Test
public void testConnection() throws Exception {
TestPacketListener listener1 = new TestPacketListener(ENetworkKey.TEST_PACKET);
TestPacketListener listener2 = new TestPacketListener(ENetworkKey.TEST_PACKET);
c1.registerListener(listener1);
c2.registerListener(listener2);
TestPacket testPackage = new TestPacket("dlkfjs", -23423);
c1.sendPacket(ENetworkKey.TEST_PACKET, testPackage);
c2.sendPacket(ENetworkKey.TEST_PACKET, testPackage);
Thread.sleep(80);
assertEquals(1, listener1.packets.size());
assertEquals(testPackage, listener1.packets.get(0));
assertEquals(1, listener2.packets.size());
assertEquals(testPackage, listener2.packets.get(0));
}
@Test
public void testMultiPackets() throws Exception {
TestPacketListener listener = new TestPacketListener(ENetworkKey.TEST_PACKET);
c2.registerListener(listener);
final int NUMBER_OF_PACKETS = 200;
for (int i = 0; i < NUMBER_OF_PACKETS; i++) {
c1.sendPacket(ENetworkKey.TEST_PACKET, new TestPacket(i));
}
Thread.sleep(30);
assertEquals(NUMBER_OF_PACKETS, listener.packets.size());
for (int i = 0; i < NUMBER_OF_PACKETS; i++) {
assertEquals(i, listener.packets.get(i).getTestInt());
}
}
@Test
public void testRoundTripTime() throws InterruptedException {
Thread.sleep(10);
assertNotNull(c1.getRoundTripTime());
assertNotNull(c2.getRoundTripTime());
assertTrue(c1.getRoundTripTime().getLastUpdated() - System.currentTimeMillis() < 5);
assertTrue(c2.getRoundTripTime().getLastUpdated() - System.currentTimeMillis() < 5);
Thread.sleep(100);
assertTrue(c1.getRoundTripTime().getLastUpdated() - System.currentTimeMillis() < 5);
assertTrue(c2.getRoundTripTime().getLastUpdated() - System.currentTimeMillis() < 5);
}
@Test
public void testCloseOneSide() throws InterruptedException {
assertFalse(c1.isClosed());
assertFalse(c2.isClosed());
c1.close();
assertTrue(c1.isClosed());
Thread.sleep(40);
assertTrue(c2.isClosed());
}
@Test
public void testCloseOtherSide() throws InterruptedException {
assertFalse(c1.isClosed());
assertFalse(c2.isClosed());
c2.close();
assertTrue(c2.isClosed());
Thread.sleep(40);
assertTrue(c1.isClosed());
}
@Test
public void testChannelClosedListener() throws InterruptedException {
final int[] closed = new int[1];
c1.setChannelClosedListener(new IChannelClosedListener() {
@Override
public void channelClosed() {
closed[0]++;
}
});
assertEquals(0, closed[0]);
c1.close();
Thread.sleep(30);
assertEquals(1, closed[0]);
Thread.sleep(150);
assertEquals(1, closed[0]);
}
@Test
public void testMultiClose() {
c1.close();
c2.close();
c1.close();
c2.close();
c1.close();
c2.close();
}
@Test
public void testSendingOnClosedChannel() {
c1.close();
c2.close();
c1.sendPacket(ENetworkKey.TEST_PACKET, new TestPacket("sdfsdf", 1434));
c2.sendPacket(ENetworkKey.TEST_PACKET, new TestPacket("dsfsw", 32423));
}
@Test
public void testSendingMessageWithoutListener() throws Exception {
c1.sendPacket(NetworkConstants.ENetworkKey.ARRAY_OF_MATCHES, new TestPacket("sdfsf���", -2342));
c2.sendPacket(NetworkConstants.ENetworkKey.ARRAY_OF_MATCHES, new TestPacket("dsfs", 4234)); // test both channels
Thread.sleep(40);
testConnection(); // now the normal test should still work.
}
@Test
public void testRemovingListener() throws Exception {
TestPacketListener listener = new TestPacketListener(ENetworkKey.TEST_PACKET);
c2.registerListener(listener);
TestPacket testPackage = new TestPacket("dsfs", 2332);
c1.sendPacket(ENetworkKey.TEST_PACKET, testPackage);
Thread.sleep(80);
assertEquals(1, listener.packets.size());
assertEquals(testPackage, listener.packets.get(0));
c2.removeListener(listener.getKeys()[0]);
c1.sendPacket(ENetworkKey.TEST_PACKET, testPackage);
Thread.sleep(80);
assertEquals(1, listener.packets.size());
}
@Test
public void testReadNotAllFromStream() throws Exception {
BufferingPacketListener<TestPacket> listener = new BufferingPacketListener<TestPacket>(ENetworkKey.TEST_PACKET,
new IDeserializingable<TestPacket>() {
@Override
public TestPacket deserialize(ENetworkKey key, DataInputStream dis) throws IOException {
dis.readInt();
return new TestPacket();
}
});
c2.registerListener(listener);
TestPacket testPacket = new TestPacket("dfsdufh", 4);
c1.sendPacket(ENetworkKey.TEST_PACKET, testPacket);
Thread.sleep(50);
assertEquals(1, listener.popBufferedPackets().size());
testConnection(); // test if connection is still ok
}
@Test
public void testReadMoreFromStream() throws Exception {
BufferingPacketListener<TestPacket> listener = new BufferingPacketListener<TestPacket>(ENetworkKey.TEST_PACKET,
new IDeserializingable<TestPacket>() {
@Override
public TestPacket deserialize(ENetworkKey key, DataInputStream dis) throws IOException {
TestPacket packet = new TestPacket();
packet.deserialize(dis);
dis.readInt(); // try to read some more bytes
dis.readUTF();
dis.readInt();
return packet;
}
});
c2.registerListener(listener);
System.out.println("DON'T WORRY, AN EXCEPTION IS EXPECTED AFTER THIS:");
TestPacket testPacket = new TestPacket("dfsdufh", 4);
c1.sendPacket(ENetworkKey.TEST_PACKET, testPacket);
Thread.sleep(100);
testConnection(); // test if connection is still ok
}
@Test
public void testRejectSendingForUnlistenedPackets() throws InterruptedException {
// construct and connect the listener for reject packets
BufferingPacketListener<RejectPacket> c1RejectListener = new BufferingPacketListener<RejectPacket>(
NetworkConstants.ENetworkKey.REJECT_PACKET,
new GenericDeserializer<RejectPacket>(RejectPacket.class));
c1.registerListener(c1RejectListener);
// send the packet for an unconnected key from the channel with a reject listener
c1.sendPacket(ENetworkKey.TEST_PACKET, new EmptyPacket());
assertEquals(0, c1RejectListener.popBufferedPackets().size());
Thread.sleep(30);
List<RejectPacket> rejects = c1RejectListener.popBufferedPackets();
assertEquals(1, rejects.size());
assertEquals(NetworkConstants.ENetworkMessage.NO_LISTENER_FOUND, rejects.get(0).getErrorMessageId());
assertEquals(ENetworkKey.TEST_PACKET, rejects.get(0).getRejectedKey());
}
@Test
public void testRejectSendingForUnlistenedPacketsLoopProtection() throws InterruptedException {
// construct and connect the listener for reject packets
BufferingPacketListener<RejectPacket> c1RejectListener = new BufferingPacketListener<RejectPacket>(
NetworkConstants.ENetworkKey.REJECT_PACKET,
new GenericDeserializer<RejectPacket>(RejectPacket.class));
c1.registerListener(c1RejectListener);
// send the packet for an unconnected key from the channel without a reject listener
// this provokes a reject packet being send back to c2 BUT this MUST NOT cause a reject packet send to c1.
c2.sendPacket(ENetworkKey.TEST_PACKET, new EmptyPacket());
assertEquals(0, c1RejectListener.popBufferedPackets().size());
Thread.sleep(50);
List<RejectPacket> rejects = c1RejectListener.popBufferedPackets();
assertEquals(0, rejects.size());
}
}