/* * TeleStax, Open Source Cloud Communications Copyright 2012. * and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * 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.mobicents.protocols.ss7.m3ua.impl.fsm; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.mobicents.protocols.ss7.m3ua.impl.scheduler.M3UAScheduler; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; /** * * @author amit bhayani * */ public class FSMTest { private M3UAScheduler m3uaScheduler = new M3UAScheduler(); private ScheduledExecutorService scheduledExecutorService = null; private volatile boolean timedOut = false; private volatile boolean stateEntered = false; private volatile boolean stateExited = false; private volatile boolean transitionHandlerCalled = false; private volatile int timeOutCount = 0; @BeforeClass public static void setUpClass() throws Exception { } @AfterClass public static void tearDownClass() throws Exception { } @BeforeMethod public void setUp() throws Exception { timedOut = false; stateEntered = false; stateExited = false; transitionHandlerCalled = false; scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); scheduledExecutorService.scheduleAtFixedRate(m3uaScheduler, 500, 500, TimeUnit.MILLISECONDS); } @AfterMethod public void tearDown() throws Exception { } @Test public void testOnExit() throws Exception { FSM fsm = new FSM("test"); fsm.createState("STATE1").setOnExit(new AsState1Exit(fsm)); fsm.createState("STATE2"); fsm.setStart("STATE1"); fsm.setEnd("STATE2"); fsm.createTransition("GoToSTATE2", "STATE1", "STATE2"); m3uaScheduler.execute(fsm); fsm.signal("GoToSTATE2"); assertTrue(stateExited); assertEquals("STATE2", fsm.getState().getName()); } @Test public void testTransitionHandler() throws Exception { FSM fsm = new FSM("test"); fsm.createState("STATE1"); fsm.createState("STATE2"); fsm.setStart("STATE1"); fsm.setEnd("STATE2"); fsm.createTransition("GoToSTATE2", "STATE1", "STATE2").setHandler(new State1ToState2Transition()); m3uaScheduler.execute(fsm); fsm.signal("GoToSTATE2"); assertTrue(transitionHandlerCalled); assertEquals("STATE2", fsm.getState().getName()); } /** * In this test we set TransitionHandler to cancel the transition and yet original timeout is to be respected * * @throws Exception */ @Test public void testNoTransitionHandler() throws Exception { FSM fsm = new FSM("test"); fsm.createState("STATE1"); fsm.createState("STATE2"); fsm.setStart("STATE1"); fsm.setEnd("STATE2"); // Transition shouldn't happen fsm.createTransition("GoToSTATE2", "STATE1", "STATE2").setHandler(new State1ToState2NoTransition()); m3uaScheduler.execute(fsm); fsm.signal("GoToSTATE2"); assertTrue(transitionHandlerCalled); assertEquals("STATE1", fsm.getState().getName()); } @Test public void testOnEnter() throws Exception { FSM fsm = new FSM("test"); fsm.createState("STATE1"); fsm.createState("STATE2").setOnEnter(new AsState2Enter(fsm)); fsm.setStart("STATE1"); fsm.setEnd("STATE2"); fsm.createTransition("GoToSTATE2", "STATE1", "STATE2"); m3uaScheduler.execute(fsm); fsm.signal("GoToSTATE2"); assertTrue(stateEntered); assertEquals("STATE2", fsm.getState().getName()); } @Test public void testTimeout() throws Exception { FSM fsm = new FSM("test"); fsm.createState("STATE1"); fsm.createState("STATE2").setOnTimeOut(new AsState2Timeout(fsm), 2000); fsm.setStart("STATE1"); fsm.setEnd("STATE2"); fsm.createTransition("GoToSTATE2", "STATE1", "STATE2"); m3uaScheduler.execute(fsm); fsm.signal("GoToSTATE2"); try { Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } assertTrue(timedOut); assertEquals("STATE2", fsm.getState().getName()); } @Test public void testTimeoutNoTransition() throws Exception { FSM fsm = new FSM("test"); fsm.createState("STATE1"); fsm.createState("STATE2").setOnTimeOut(new AsState2Timeout(fsm), 2000); fsm.createState("STATE3"); fsm.setStart("STATE1"); fsm.setEnd("STATE2"); fsm.createTransition("GoToSTATE2", "STATE1", "STATE2"); fsm.createTransition("GoToSTATE3", "STATE2", "STATE3").setHandler(new NoTransition()); m3uaScheduler.execute(fsm); fsm.signal("GoToSTATE2"); assertEquals("STATE2", fsm.getState().getName()); fsm.signal("GoToSTATE3"); try { Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } assertTrue(timedOut); assertEquals("STATE2", fsm.getState().getName()); } @Test public void testTimeoutTransition() throws Exception { FSM fsm = new FSM("test"); fsm.createState("STATE1"); fsm.createState("STATE2"); fsm.createState("STATE3"); fsm.setStart("STATE1"); fsm.setEnd("STATE3"); fsm.createTransition("GoToSTATE2", "STATE1", "STATE2"); fsm.createTimeoutTransition("STATE2", "STATE2", 1000l).setHandler(new State2TimeoutTransition()); m3uaScheduler.execute(fsm); fsm.signal("GoToSTATE2"); try { Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } assertTrue((2 <= timeOutCount) && (timeOutCount <= 3)); assertEquals("STATE2", fsm.getState().getName()); } class AsState1Exit implements FSMStateEventHandler { private FSM fsm; public AsState1Exit(FSM fsm) { this.fsm = fsm; } public void onEvent(FSMState state) { stateExited = true; } } class AsState2Timeout implements FSMStateEventHandler { private FSM fsm; public AsState2Timeout(FSM fsm) { this.fsm = fsm; } public void onEvent(FSMState state) { timedOut = true; } } class AsState2Enter implements FSMStateEventHandler { private FSM fsm; public AsState2Enter(FSM fsm) { this.fsm = fsm; } public void onEvent(FSMState state) { stateEntered = true; } } class State1ToState2Transition implements TransitionHandler { @Override public boolean process(FSMState state) { transitionHandlerCalled = true; return true; } } class State2TimeoutTransition implements TransitionHandler { @Override public boolean process(FSMState state) { timeOutCount++; return true; } } class State1ToState2NoTransition implements TransitionHandler { @Override public boolean process(FSMState state) { transitionHandlerCalled = true; return false; } } class NoTransition implements TransitionHandler { @Override public boolean process(FSMState state) { return false; } } }