/* * TeleStax, Open Source Cloud Communications * Copyright 2011-2016, 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.control.mgcp.connection; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.only; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.concurrent.Executors; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.restcomm.media.control.mgcp.connection.MgcpConnectionState; import org.restcomm.media.control.mgcp.connection.MgcpLocalConnection; import org.restcomm.media.control.mgcp.exception.MgcpConnectionException; import org.restcomm.media.control.mgcp.message.LocalConnectionOptions; import org.restcomm.media.control.mgcp.pkg.MgcpEventObserver; import org.restcomm.media.control.mgcp.pkg.MgcpEventProvider; import org.restcomm.media.control.mgcp.pkg.r.rto.RtpTimeoutEvent; import org.restcomm.media.rtp.ChannelsManager; import org.restcomm.media.rtp.LocalDataChannel; import org.restcomm.media.rtp.channels.AudioChannel; import org.restcomm.media.rtp.channels.MediaChannelProvider; import org.restcomm.media.sdp.format.AVProfile; import com.google.common.util.concurrent.ListeningScheduledExecutorService; import com.google.common.util.concurrent.MoreExecutors; /** * @author Henrique Rosa (henrique.rosa@telestax.com) * */ public class MgcpLocalConnectionTest { private ListeningScheduledExecutorService executor; @Before public void before() { this.executor = MoreExecutors.listeningDecorator(Executors.newScheduledThreadPool(1)); } public void after() { this.executor.shutdownNow(); this.executor = null; } @Test public void testMaxDurationTimerWhenHalfOpen() throws MgcpConnectionException, InterruptedException { // given final int callId = 1; final int identifier = 1; final int halfOpenTimeout = 2; final int openTimeout = 3; final MgcpEventObserver observer = mock(MgcpEventObserver.class); final ArgumentCaptor<RtpTimeoutEvent> timeoutCaptor = ArgumentCaptor.forClass(RtpTimeoutEvent.class); final LocalDataChannel dataChannel = mock(LocalDataChannel.class); final MgcpEventProvider eventProvider = mock(MgcpEventProvider.class); final ChannelsManager channelProvider = mock(ChannelsManager.class); // when when(channelProvider.getLocalChannel()).thenReturn(dataChannel); final MgcpLocalConnection connection = new MgcpLocalConnection(identifier, callId, halfOpenTimeout, openTimeout, eventProvider, channelProvider, this.executor); connection.observe(observer); connection.halfOpen(new LocalConnectionOptions()); Thread.sleep(halfOpenTimeout * 1000 + 200); // then assertEquals(MgcpConnectionState.CLOSED, connection.state); verify(observer, only()).onEvent(eq(connection), timeoutCaptor.capture()); assertNotNull(timeoutCaptor.getValue()); assertEquals(halfOpenTimeout, timeoutCaptor.getValue().getTimeout()); } @Test public void testMaxDurationTimerWhenOpen() throws MgcpConnectionException, InterruptedException { // given final int callId = 1; final int openTimeout = 4; final int halfOpenTimeout = openTimeout / 2; final MgcpEventObserver observer = mock(MgcpEventObserver.class); final ArgumentCaptor<RtpTimeoutEvent> timeoutCaptor = ArgumentCaptor.forClass(RtpTimeoutEvent.class); final LocalDataChannel dataChannel = mock(LocalDataChannel.class); final ChannelsManager channelProvider = mock(ChannelsManager.class); final MgcpEventProvider eventProvider = mock(MgcpEventProvider.class); // when when(channelProvider.getLocalChannel()).thenReturn(dataChannel); final MgcpLocalConnection connection1 = new MgcpLocalConnection(1, callId, halfOpenTimeout, openTimeout, eventProvider, channelProvider, this.executor); connection1.observe(observer); final String sdp1 = connection1.halfOpen(new LocalConnectionOptions()); final MgcpLocalConnection connection2 = new MgcpLocalConnection(2, callId, halfOpenTimeout, openTimeout, eventProvider, channelProvider, this.executor); connection2.observe(observer); connection2.open(sdp1); // then Thread.sleep(halfOpenTimeout * 1000 + 200); assertEquals(MgcpConnectionState.CLOSED, connection1.state); verify(observer, times(1)).onEvent(eq(connection1), timeoutCaptor.capture()); assertNotNull(timeoutCaptor.getValue()); assertEquals(halfOpenTimeout, timeoutCaptor.getValue().getTimeout()); assertEquals(MgcpConnectionState.OPEN, connection2.state); Thread.sleep(halfOpenTimeout * 1000 + 200); assertEquals(MgcpConnectionState.CLOSED, connection2.state); verify(observer, times(1)).onEvent(eq(connection2), timeoutCaptor.capture()); assertNotNull(timeoutCaptor.getValue()); assertEquals(openTimeout, timeoutCaptor.getValue().getTimeout()); } @Test public void testHalfOpenTimerCancelationWhenMovingToOpen() throws MgcpConnectionException, InterruptedException { // given final int openTimeout = 4; final int halfOpenTimeout = openTimeout / 2; final MgcpEventObserver observer = mock(MgcpEventObserver.class); final ArgumentCaptor<RtpTimeoutEvent> timeoutCaptor = ArgumentCaptor.forClass(RtpTimeoutEvent.class); final LocalDataChannel dataChannel = mock(LocalDataChannel.class); final ChannelsManager channelProvider = mock(ChannelsManager.class); final MgcpEventProvider eventProvider = mock(MgcpEventProvider.class); // when when(channelProvider.getLocalChannel()).thenReturn(dataChannel); final MgcpLocalConnection connection1 = new MgcpLocalConnection(1, halfOpenTimeout, openTimeout, eventProvider, channelProvider, this.executor); connection1.observe(observer); final String sdp1 = connection1.halfOpen(new LocalConnectionOptions()); final MgcpLocalConnection connection2 = new MgcpLocalConnection(2, halfOpenTimeout, openTimeout, eventProvider, channelProvider, this.executor); connection2.observe(observer); final String sdp2 = connection2.open(sdp1); connection1.open(sdp2); // then Thread.sleep(halfOpenTimeout * 1000 + 200); assertEquals(MgcpConnectionState.OPEN, connection1.state); assertEquals(MgcpConnectionState.OPEN, connection2.state); Thread.sleep(halfOpenTimeout * 1000 + 200); assertEquals(MgcpConnectionState.CLOSED, connection1.state); verify(observer, times(1)).onEvent(eq(connection1), timeoutCaptor.capture()); assertNotNull(timeoutCaptor.getValue()); assertEquals(openTimeout, timeoutCaptor.getValue().getTimeout()); assertEquals(MgcpConnectionState.CLOSED, connection2.state); verify(observer, times(1)).onEvent(eq(connection2), timeoutCaptor.capture()); assertNotNull(timeoutCaptor.getValue()); assertEquals(openTimeout, timeoutCaptor.getValue().getTimeout()); } @Test public void testInactiveHalfOpenTimer() throws MgcpConnectionException, InterruptedException { // given final int identifier = 1; final int halfOpenTimeout = 0; final int openTimeout = 4; final MgcpEventObserver observer = mock(MgcpEventObserver.class); final ArgumentCaptor<RtpTimeoutEvent> timeoutCaptor = ArgumentCaptor.forClass(RtpTimeoutEvent.class); final LocalDataChannel dataChannel = mock(LocalDataChannel.class); final ChannelsManager channelProvider = mock(ChannelsManager.class); final MgcpEventProvider eventProvider = mock(MgcpEventProvider.class); // when when(channelProvider.getLocalChannel()).thenReturn(dataChannel); final MgcpLocalConnection connection = new MgcpLocalConnection(identifier, halfOpenTimeout, openTimeout, eventProvider, channelProvider, this.executor); connection.observe(observer); connection.halfOpen(new LocalConnectionOptions()); Thread.sleep(openTimeout * 1000); // then assertEquals(MgcpConnectionState.HALF_OPEN, connection.state); verify(observer, never()).onEvent(eq(connection), timeoutCaptor.capture()); } @Test public void testInactiveOpenTimer() throws MgcpConnectionException, InterruptedException { // given final int callId = 1; final int connectionId1 = 1; final int connectionId2 = 2; final int openTimeout = 0; final int halfOpenTimeout = 2; final MgcpEventObserver observer = mock(MgcpEventObserver.class); final ArgumentCaptor<RtpTimeoutEvent> timeoutCaptor = ArgumentCaptor.forClass(RtpTimeoutEvent.class); final LocalDataChannel dataChannel = mock(LocalDataChannel.class); final ChannelsManager channelProvider = mock(ChannelsManager.class); final MgcpEventProvider eventProvider = mock(MgcpEventProvider.class); // when when(channelProvider.getLocalChannel()).thenReturn(dataChannel); final MgcpLocalConnection connection1 = new MgcpLocalConnection(connectionId1, callId, halfOpenTimeout, openTimeout, eventProvider, channelProvider, this.executor); connection1.observe(observer); final String sdp1 = connection1.halfOpen(new LocalConnectionOptions()); final MgcpLocalConnection connection2 = new MgcpLocalConnection(connectionId2, callId, halfOpenTimeout, openTimeout, eventProvider, channelProvider, this.executor); connection2.observe(observer); connection2.open(sdp1); // then Thread.sleep(halfOpenTimeout * 1000 + 200); assertEquals(MgcpConnectionState.CLOSED, connection1.state); verify(observer, times(1)).onEvent(eq(connection1), timeoutCaptor.capture()); assertNotNull(timeoutCaptor.getValue()); assertEquals(halfOpenTimeout, timeoutCaptor.getValue().getTimeout()); assertEquals(MgcpConnectionState.OPEN, connection2.state); Thread.sleep(halfOpenTimeout * 1000 + 200); assertEquals(MgcpConnectionState.OPEN, connection2.state); verify(observer, never()).onEvent(eq(connection2), timeoutCaptor.capture()); } }