org.restcomm.media.network.netty.channel.AsyncNettyNetworkChannelTest.java Source code

Java tutorial

Introduction

Here is the source code for org.restcomm.media.network.netty.channel.AsyncNettyNetworkChannelTest.java

Source

/*
 * TeleStax, Open Source Cloud Communications
 * Copyright 2011-2017, Telestax Inc and individual contributors
 * by the @authors tag. 
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

package org.restcomm.media.network.netty.channel;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.restcomm.media.network.netty.NettyNetworkManager;

import com.google.common.util.concurrent.FutureCallback;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.channel.DefaultChannelProgressivePromise;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.util.concurrent.EventExecutor;

/**
 * @author Henrique Rosa (henrique.rosa@telestax.com)
 *
 */
@RunWith(PowerMockRunner.class)
@PrepareForTest({ Channel.class, NioDatagramChannel.class, DatagramChannel.class })
public class AsyncNettyNetworkChannelTest {

    private DatagramChannel remotePeer;
    private EventLoopGroup eventGroup;
    private EventExecutor executor;

    @After
    public void after() {
        if (this.remotePeer != null) {
            if (this.remotePeer.isOpen()) {
                try {
                    this.remotePeer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            this.remotePeer = null;
        }

        if (this.executor != null) {
            if (!this.executor.isShutdown()) {
                this.executor.shutdownGracefully(0L, 0L, TimeUnit.MILLISECONDS);
            }
            this.executor = null;
        }

        if (this.eventGroup != null) {
            this.eventGroup.shutdownGracefully(0L, 0L, TimeUnit.MILLISECONDS);
            this.eventGroup = null;
        }
    }

    @SuppressWarnings("unchecked")
    @Test
    public void testLifecycle() {
        // given
        final SocketAddress localAddress = new InetSocketAddress("127.0.0.1", 2427);
        final SocketAddress remoteAddress = new InetSocketAddress("127.0.0.1", 2727);

        final ChannelHandler channelHandler = mock(ChannelHandler.class);
        this.eventGroup = new NioEventLoopGroup();
        final Bootstrap bootstrap = new Bootstrap().group(eventGroup).handler(channelHandler)
                .channel(NioDatagramChannel.class);
        final NettyNetworkManager networkManager = new NettyNetworkManager(bootstrap);
        final AsyncNettyNetworkChannel<Object> networkChannel = new AsyncNettyNetworkChannel<>(networkManager);

        final FutureCallback<Void> openCallback = mock(FutureCallback.class);
        final FutureCallback<Void> bindCallback = mock(FutureCallback.class);
        final FutureCallback<Void> connectCallback = mock(FutureCallback.class);
        final FutureCallback<Void> disconnectCallback = mock(FutureCallback.class);
        final FutureCallback<Void> closeCallback = mock(FutureCallback.class);

        // when - open
        networkChannel.open(openCallback);

        // then
        verify(openCallback, timeout(100)).onSuccess(null);
        assertTrue(networkChannel.isOpen());
        assertFalse(networkChannel.isBound());
        assertFalse(networkChannel.isConnected());

        // when - bind
        networkChannel.bind(localAddress, bindCallback);

        // then
        verify(bindCallback, timeout(100)).onSuccess(null);
        assertTrue(networkChannel.isOpen());
        assertTrue(networkChannel.isBound());
        assertFalse(networkChannel.isConnected());

        // when - connect
        networkChannel.connect(remoteAddress, connectCallback);

        // then
        verify(connectCallback, timeout(100)).onSuccess(null);
        assertTrue(networkChannel.isOpen());
        assertTrue(networkChannel.isBound());
        assertTrue(networkChannel.isConnected());

        // when - disconnect
        networkChannel.disconnect(disconnectCallback);

        // then
        verify(disconnectCallback, timeout(100)).onSuccess(null);
        assertTrue(networkChannel.isOpen());
        assertTrue(networkChannel.isBound());
        assertFalse(networkChannel.isConnected());

        // when - close
        networkChannel.close(closeCallback);

        // then
        verify(closeCallback, timeout(100)).onSuccess(null);
        assertFalse(networkChannel.isOpen());
        assertFalse(networkChannel.isBound());
        assertFalse(networkChannel.isConnected());
    }

    @SuppressWarnings("unchecked")
    @Test
    public void testSendConnected() throws Exception {
        // given
        final String message = "hello";
        final byte[] data = new byte[message.getBytes().length];
        final ByteBuffer dataBuffer = ByteBuffer.allocate(data.length);

        final SocketAddress localAddress = new InetSocketAddress("127.0.0.1", 2427);
        final SocketAddress remoteAddress = new InetSocketAddress("127.0.0.1", 2727);

        final ChannelHandler channelHandler = new ObjectChannelHandler();
        this.eventGroup = new NioEventLoopGroup();
        final Bootstrap bootstrap = new Bootstrap().group(eventGroup).handler(channelHandler)
                .channel(NioDatagramChannel.class);
        final NettyNetworkManager networkManager = new NettyNetworkManager(bootstrap);
        final AsyncNettyNetworkChannel<Object> networkChannel = new AsyncNettyNetworkChannel<>(networkManager);

        final FutureCallback<Void> openCallback = mock(FutureCallback.class);
        final FutureCallback<Void> bindCallback = mock(FutureCallback.class);
        final FutureCallback<Void> connectCallback = mock(FutureCallback.class);
        final FutureCallback<Void> sendCallback = mock(FutureCallback.class);
        final FutureCallback<Void> closeCallback = mock(FutureCallback.class);

        // when
        this.remotePeer = DatagramChannel.open();
        this.remotePeer.configureBlocking(false);
        this.remotePeer.bind(remoteAddress);

        networkChannel.open(openCallback);
        verify(openCallback, timeout(100)).onSuccess(null);

        networkChannel.bind(localAddress, bindCallback);
        verify(bindCallback, timeout(100)).onSuccess(null);

        networkChannel.connect(remoteAddress, connectCallback);
        verify(connectCallback, timeout(100)).onSuccess(null);

        networkChannel.send(Unpooled.copiedBuffer(message.getBytes()), sendCallback);
        verify(sendCallback, timeout(100)).onSuccess(null);

        Thread.sleep(20);
        final SocketAddress msgSender = remotePeer.receive(dataBuffer);
        dataBuffer.rewind();
        dataBuffer.get(data);

        this.remotePeer.close();
        networkChannel.close(closeCallback);

        // then
        assertEquals(localAddress, msgSender);
        assertEquals(message, new String(data));
    }

    @SuppressWarnings("unchecked")
    @Test
    public void testSendDisconnected() throws Exception {
        // given
        final String message = "hello";
        final byte[] data = new byte[message.getBytes().length];
        final ByteBuffer dataBuffer = ByteBuffer.allocate(data.length);

        final SocketAddress localAddress = new InetSocketAddress("127.0.0.1", 2427);
        final SocketAddress remoteAddress = new InetSocketAddress("127.0.0.1", 2727);

        final ChannelHandler channelHandler = new ObjectChannelHandler();
        this.eventGroup = new NioEventLoopGroup();
        final Bootstrap bootstrap = new Bootstrap().group(eventGroup).handler(channelHandler)
                .channel(NioDatagramChannel.class);
        final NettyNetworkManager networkManager = new NettyNetworkManager(bootstrap);
        final AsyncNettyNetworkChannel<Object> networkChannel = new AsyncNettyNetworkChannel<>(networkManager);

        final FutureCallback<Void> openCallback = mock(FutureCallback.class);
        final FutureCallback<Void> bindCallback = mock(FutureCallback.class);
        final FutureCallback<Void> sendCallback = mock(FutureCallback.class);
        final FutureCallback<Void> closeCallback = mock(FutureCallback.class);

        // when
        this.remotePeer = DatagramChannel.open();
        this.remotePeer.configureBlocking(false);
        this.remotePeer.bind(remoteAddress);

        networkChannel.open(openCallback);
        verify(openCallback, timeout(100)).onSuccess(null);

        networkChannel.bind(localAddress, bindCallback);
        verify(bindCallback, timeout(100)).onSuccess(null);

        networkChannel.send(Unpooled.copiedBuffer(message.getBytes()), remoteAddress, sendCallback);
        verify(sendCallback, timeout(100)).onSuccess(null);

        Thread.sleep(20);
        final SocketAddress msgSender = remotePeer.receive(dataBuffer);
        dataBuffer.rewind();
        dataBuffer.get(data);

        this.remotePeer.close();
        networkChannel.close(closeCallback);

        // then
        assertEquals(localAddress, msgSender);
        assertEquals(message, new String(data));
    }

    @SuppressWarnings("unchecked")
    @Test
    public void testReceive() throws Exception {
        // given
        final String message = "hello";
        final byte[] data = message.getBytes();
        final ByteBuffer dataBuffer = ByteBuffer.allocate(data.length);

        final SocketAddress localAddress = new InetSocketAddress("127.0.0.1", 2427);
        final SocketAddress remoteAddress = new InetSocketAddress("127.0.0.1", 2727);

        final ObjectChannelHandler channelHandler = new ObjectChannelHandler();
        this.eventGroup = new NioEventLoopGroup();
        final Bootstrap bootstrap = new Bootstrap().group(eventGroup).handler(channelHandler)
                .channel(NioDatagramChannel.class);
        final NettyNetworkManager networkManager = new NettyNetworkManager(bootstrap);
        final AsyncNettyNetworkChannel<String> networkChannel = new AsyncNettyNetworkChannel<>(networkManager);

        final FutureCallback<Void> openCallback = mock(FutureCallback.class);
        final FutureCallback<Void> bindCallback = mock(FutureCallback.class);
        final FutureCallback<Void> closeCallback = mock(FutureCallback.class);

        // when
        this.remotePeer = DatagramChannel.open();
        this.remotePeer.configureBlocking(false);
        this.remotePeer.bind(remoteAddress);

        networkChannel.open(openCallback);
        verify(openCallback, timeout(100)).onSuccess(null);

        networkChannel.bind(localAddress, bindCallback);
        verify(bindCallback, timeout(100)).onSuccess(null);

        dataBuffer.put(data);
        dataBuffer.flip();
        int sent = remotePeer.send(dataBuffer, localAddress);

        Thread.sleep(20);

        this.remotePeer.close();
        networkChannel.close(closeCallback);

        // then
        assertEquals(sent, data.length);
        assertEquals(message, channelHandler.getMessage());
    }

    private class ObjectChannelHandler extends MessageToMessageDecoder<DatagramPacket> {

        private String message = "";

        public String getMessage() {
            return message;
        }

        @Override
        protected void decode(ChannelHandlerContext ctx, DatagramPacket msg, List<Object> out) throws Exception {
            ByteBuf in = msg.content();
            byte[] dst = new byte[in.readableBytes()];
            in.readBytes(dst);
            this.message = new String(dst);
        }

    }

    @SuppressWarnings("unchecked")
    @Test
    public void testSendToRemoteWhenDisconnected() throws Exception {
        // given
        final String message = "hello";
        final SocketAddress localAddress = new InetSocketAddress("127.0.0.1", 2427);

        final ChannelHandler channelHandler = new ObjectChannelHandler();
        this.eventGroup = new NioEventLoopGroup();
        final Bootstrap bootstrap = new Bootstrap().group(eventGroup).handler(channelHandler)
                .channel(NioDatagramChannel.class);
        final NettyNetworkManager networkManager = new NettyNetworkManager(bootstrap);
        final AsyncNettyNetworkChannel<Object> networkChannel = new AsyncNettyNetworkChannel<>(networkManager);

        final FutureCallback<Void> openCallback = mock(FutureCallback.class);
        final FutureCallback<Void> bindCallback = mock(FutureCallback.class);
        final FutureCallback<Void> sendCallback = mock(FutureCallback.class);
        final FutureCallback<Void> closeCallback = mock(FutureCallback.class);

        // when
        networkChannel.open(openCallback);
        verify(openCallback, timeout(100)).onSuccess(null);

        networkChannel.bind(localAddress, bindCallback);
        verify(bindCallback, timeout(100)).onSuccess(null);

        networkChannel.send(Unpooled.copiedBuffer(message.getBytes()), sendCallback);
        networkChannel.close(closeCallback);

        // then
        verify(sendCallback, times(1)).onFailure(any(IllegalStateException.class));
    }

    @SuppressWarnings("unchecked")
    @Test
    public void testSendToSpecificRemoteWhenConnected() throws Exception {
        // given
        final String message = "hello";
        final SocketAddress localAddress = new InetSocketAddress("127.0.0.1", 2427);
        final SocketAddress remoteAddress = new InetSocketAddress("127.0.0.1", 2727);

        final ChannelHandler channelHandler = new ObjectChannelHandler();
        this.eventGroup = new NioEventLoopGroup();
        final Bootstrap bootstrap = new Bootstrap().group(eventGroup).handler(channelHandler)
                .channel(NioDatagramChannel.class);
        final NettyNetworkManager networkManager = new NettyNetworkManager(bootstrap);
        final AsyncNettyNetworkChannel<Object> networkChannel = new AsyncNettyNetworkChannel<>(networkManager);

        final FutureCallback<Void> openCallback = mock(FutureCallback.class);
        final FutureCallback<Void> bindCallback = mock(FutureCallback.class);
        final FutureCallback<Void> connectCallback = mock(FutureCallback.class);
        final FutureCallback<Void> sendCallback = mock(FutureCallback.class);
        final FutureCallback<Void> closeCallback = mock(FutureCallback.class);

        // when
        networkChannel.open(openCallback);
        verify(openCallback, timeout(100)).onSuccess(null);

        networkChannel.bind(localAddress, bindCallback);
        verify(bindCallback, timeout(100)).onSuccess(null);

        networkChannel.connect(remoteAddress, connectCallback);
        verify(connectCallback, timeout(100)).onSuccess(null);

        networkChannel.send(Unpooled.copiedBuffer(message.getBytes()), remoteAddress, sendCallback);
        networkChannel.close(closeCallback);

        // then
        verify(sendCallback, times(1)).onFailure(any(IllegalStateException.class));
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    @Test
    public void testOpenFailure() {
        // given
        this.eventGroup = new NioEventLoopGroup();
        final NettyNetworkManager networkManager = mock(NettyNetworkManager.class);
        final AsyncNettyNetworkChannel<Object> networkChannel = new AsyncNettyNetworkChannel<>(networkManager);
        final FutureCallback<Void> openCallback = mock(FutureCallback.class);
        final Exception exception = new RuntimeException("Testing purposes!");

        // when - open
        doAnswer(new Answer() {

            @Override
            public Object answer(InvocationOnMock invocation) throws Throwable {
                final FutureCallback callback = invocation.getArgumentAt(0, FutureCallback.class);
                callback.onFailure(exception);
                return null;
            }

        }).when(networkManager).openChannel(any(FutureCallback.class));
        networkChannel.open(openCallback);

        // then
        verify(openCallback, timeout(100)).onFailure(exception);
        assertFalse(networkChannel.isOpen());
        assertFalse(networkChannel.isBound());
        assertFalse(networkChannel.isConnected());
    }

    @SuppressWarnings("unchecked")
    @Test
    public void testBindFailure() {
        // given
        final SocketAddress localAddress = new InetSocketAddress("127.0.0.1", 2427);

        final ChannelFuture channelBindFuture = mock(ChannelFuture.class);
        final ChannelFuture channelCloseFuture = mock(ChannelFuture.class);
        final Channel channel = mock(Channel.class);
        final ChannelHandler channelHandler = mock(ChannelHandler.class);

        this.eventGroup = new NioEventLoopGroup();
        final Bootstrap bootstrap = new Bootstrap().group(eventGroup).handler(channelHandler)
                .channel(NioDatagramChannel.class);
        final NettyNetworkManager networkManager = new NettyNetworkManager(bootstrap);
        final NettyNetworkManager networkManagerSpy = spy(networkManager);
        final AsyncNettyNetworkChannel<Object> networkChannel = new AsyncNettyNetworkChannel<>(networkManagerSpy);

        final FutureCallback<Void> openCallback = mock(FutureCallback.class);
        final FutureCallback<Void> bindCallback = mock(FutureCallback.class);
        final Exception exception = new RuntimeException("Testing purposes!");

        when(channel.bind(localAddress)).thenReturn(channelBindFuture);
        doAnswer(new Answer<Void>() {

            @Override
            public Void answer(InvocationOnMock invocation) throws Throwable {
                final FutureCallback<Channel> callback = invocation.getArgumentAt(0, FutureCallback.class);
                callback.onSuccess(channel);
                return null;
            }

        }).when(networkManagerSpy).openChannel(any(FutureCallback.class));
        doAnswer(new Answer<Void>() {

            @Override
            public Void answer(InvocationOnMock invocation) throws Throwable {
                final ChannelFutureListener listener = invocation.getArgumentAt(0, ChannelFutureListener.class);
                final ChannelPromise promise = new DefaultChannelProgressivePromise(channel,
                        mock(EventExecutor.class));
                promise.setFailure(exception);
                listener.operationComplete(promise);
                return null;
            }

        }).when(channelBindFuture).addListener(any(ChannelFutureListener.class));
        when(channel.close()).thenReturn(channelCloseFuture);

        // when - open
        networkChannel.open(openCallback);
        networkChannel.bind(localAddress, bindCallback);

        // then
        verify(bindCallback, timeout(100)).onFailure(exception);
        assertFalse(networkChannel.isOpen());
        assertFalse(networkChannel.isBound());
        assertFalse(networkChannel.isConnected());
    }

    // @SuppressWarnings("unchecked")
    // @Test
    // public void testConnectAsyncFailure() throws Exception {
    // // given
    // final SocketAddress localAddress = new InetSocketAddress("127.0.0.1", 2427);
    // final SocketAddress remoteAddress = new InetSocketAddress("127.0.0.1", 2727);
    // final Channel channel = mock(Channel.class);
    // final NettyNetworkManager networkManager = mock(NettyNetworkManager.class);
    // final AsynchronousNettyNetworkChannel<Object> networkChannel = new AsynchronousNettyNetworkChannel<>(networkManager);
    // this.executor = new DefaultEventExecutor();
    // final ChannelPromise bindPromise = new DefaultChannelPromise(channel, executor);
    // final ChannelPromise connectPromise = new DefaultChannelPromise(channel, executor);
    // final FutureCallback<Void> callback = mock(FutureCallback.class);
    // final Exception exception = new RuntimeException("Testing purposes!");
    //
    // // when
    // when(networkManager.openChannel()).thenReturn(channel);
    // when(channel.isOpen()).thenReturn(true);
    // when(channel.localAddress()).thenReturn(localAddress);
    // when(channel.remoteAddress()).thenReturn(null);
    // when(channel.bind(localAddress)).thenReturn(bindPromise);
    // when(channel.connect(remoteAddress)).thenReturn(connectPromise);
    // bindPromise.setSuccess();
    // connectPromise.setFailure(exception);
    //
    // networkChannel.open();
    // networkChannel.bind(localAddress);
    // networkChannel.connect(remoteAddress, callback);
    //
    // // then
    // verify(networkManager, times(1)).openChannel();
    // verify(channel, times(1)).bind(localAddress);
    // verify(callback, timeout(50)).onFailure(exception);
    //
    // assertTrue(networkChannel.isOpen());
    // assertTrue(networkChannel.isBound());
    // assertFalse(networkChannel.isConnected());
    // }
}