<commit_before>/*
 *    ALMA - Atacama Large Millimiter Array
 *    (c) European Southern Observatory, 2002
 *    Copyright by ESO (in the framework of the ALMA collaboration),
 *    All rights reserved
 *
 *    This library 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 library 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 library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA 02111-1307  USA
 */
package alma.ACS.MasterComponentImpl.statemachine;

import java.util.logging.Logger;

import junit.framework.TestCase;

import alma.ACS.MasterComponentImpl.StateChangeSemaphore;
import alma.acs.genfw.runtime.sm.AcsState;
import alma.acs.genfw.runtime.sm.AcsStateActionException;
import alma.acs.genfw.runtime.sm.AcsStateChangeListener;
import alma.acs.genfw.runtime.sm.AcsStateIllegalEventException;
import alma.acs.genfw.runtime.sm.AcsStateUtil;


/**
 * Tests the state machine from <code>alma.ACS.MasterComponentImpl.statemachine</code>
 * without the Master component on top of it. No running ACS needed.
 *  
 * @author hsommer
 * created Mar 3, 2004 3:27:56 PM
 */
public class StateMachineTest extends TestCase implements AcsStateChangeListener
{
    private AlmaSubsystemContext m_context;
    private DummyActionImpl m_actionImpl;
	private Logger m_logger;
	
	private MyStateChangeSemaphore m_sync;
	
	
    public void setUp() {
    	m_logger = Logger.getLogger("StateMachineTest");
    	m_actionImpl = new DummyActionImpl(m_logger);
        m_context = new AlmaSubsystemContext(m_actionImpl, m_logger);
        m_context.addAcsStateChangeListener(this);
        
        m_sync = new MyStateChangeSemaphore();
        m_context.addAcsStateChangeListener(m_sync);
    }

	/**
	 * @see alma.ACS.MasterComponentImpl.statemachine.AcsStateChangeListener#stateChangedNotify(alma.ACS.MasterComponentImpl.statemachine.AcsState[], alma.ACS.MasterComponentImpl.statemachine.AcsState[])
	 */
	public void stateChangedNotify(AcsState[] oldStateHierarchy, AcsState[] currentStateHierarchy) 
	{
		String oldHi = AcsStateUtil.stateHierarchyToString(oldStateHierarchy);
		String newHi = AcsStateUtil.stateHierarchyToString(currentStateHierarchy);
		m_logger.info("state machine switched from " + oldHi + " to " + newHi);
	}

	
    public void testLegalLifecycle() throws Exception 
	{
        m_logger.info("============ starting testLegalLifecycle ===========");
        
        m_logger.info("---> Event initPass1 will be sent.");
        m_sync.reset();
        m_context.initPass1();
        m_sync.waitForStateChanges(2); // wait for asynchronous do method to trigger state transition toward PreInitialized
        
        m_logger.info("---> Event initPass2 will be sent.");
        m_sync.reset();
        m_context.initPass2();
        m_sync.waitForStateChanges(2); // wait for asynchronous do method to trigger state transition toward Online
        
        m_logger.info("---> Event start will be sent.");
        m_context.start();
        m_logger.info("---> Event start will be sent again.");
        m_context.start();
        m_logger.info("---> Event stop will be sent.");
        m_context.stop();
        
        m_logger.info("---> Event shutdownPass1 will be sent.");
        m_sync.reset();
        m_context.shutdownPass1();
        m_sync.waitForStateChanges(2); // wait for state transition toward PreShutdown
        
        m_logger.info("---> Event shutdownPass2 will be sent.");
        m_sync.reset();
        m_context.shutdownPass2();
        m_sync.waitForStateChanges(2); // wait for state transition toward Shutdown
        
        m_logger.info("============ testLegalLifecycle successful! ===========\n");
    }

    
    public void testIllegalEvent() throws Exception {
        m_logger.info("============ starting testIllegalEvent ===========");

        m_sync.reset();
        m_context.initPass1();
        m_sync.waitForStateChanges(2); // wait for asynchronous do method to trigger state transition toward PreInitialized
        
        try {
        	// illegal event, since we're in "INITIALIZING_PASS1"
			m_context.start();
			fail("AcsStateIllegalEventException expected!");
		}
		catch (AcsStateIllegalEventException e) {
			// that's fine...
		}
		
        m_logger.info("============ testIllegalEvent successful! ===========\n");
    }

    
    public void testActionException() throws Exception 
    {
        m_logger.info("============ starting testActionException ===========");

        m_actionImpl.throwExInInitPass1(true);    	

        m_sync.reset();
        m_context.initPass1();
        m_sync.waitForStateChanges(2); // wait for asynchronous do method to trigger state transition toward PreInitialized
        
        // the action exception should have brought us into ERROR by now...
        try {
			m_context.initPass2();
			fail("AcsStateIllegalEventException expected, with state machine in ERROR state");
		}
		catch (AcsStateIllegalEventException e) {
			assertEquals("illegal event 'initPass2' in state 'ERROR'.", e.getMessage());
		}
        // let's get out of error again...
        m_context.shutdownPass1();
        m_sync.waitForStateChanges(2); // wait for asynchronous do method to trigger state transition toward         m_sync.waitForStateChanges(2); // wait for asynchronous do method to trigger state transition toward PreInitialized

        m_context.shutdownPass2();
        
        m_logger.info("============ testActionException successful! ===========\n");
    }

    


    /**
     * Test implementation of the state machine's action interface.
     * Methods will be called by the state machine.
     */
    private static class DummyActionImpl implements AlmaSubsystemActions 
	{
    	private Logger m_actionLogger;
		private boolean m_throwExInInitPass1;
    	
    	DummyActionImpl(Logger logger) {
    		m_actionLogger = logger;
    		m_throwExInInitPass1 = false;
    	}
    	
    	/**
    	 * Determines the optional test feature of letting {@link #initSubsysPass1()} 
    	 * throw an exception.
    	 */
    	void throwExInInitPass1(boolean throwEx) {
    		m_throwExInInitPass1 = throwEx;
    	}

    	
        public synchronized void initSubsysPass1() throws AcsStateActionException {
            if (m_throwExInInitPass1) {
                log("initSubsysPass1 (will throw AcsStateActionException)");  
                throw new AcsStateActionException("sorry, just a test: initPass1 failed!");          	
            }
            else {
            	log("initSubsysPass1");
            }            
        }

        public synchronized void initSubsysPass2() {
           	log("initSubsysPass2");
           	try {
				Thread.sleep(1000);
			}
			catch (InterruptedException e) {
				e.printStackTrace();
			}
        }

        public synchronized void reinitSubsystem() {
            log("reinitSubsystem");
        }

        public synchronized void shutDownSubsysPass1() {
            log("shutDownSubsysPass1");
        }

        public synchronized void shutDownSubsysPass2() {
            log("shutDownSubsysPass2");
        }<commit_msg>uses AcsJIllegalStateEventEx with new fields 'Event' and 'State' instead of old AcsStateIllegalEventException. Asserts the expected state at various places.<commit_after>/*
 *    ALMA - Atacama Large Millimiter Array
 *    (c) European Southern Observatory, 2002
 *    Copyright by ESO (in the framework of the ALMA collaboration),
 *    All rights reserved
 *
 *    This library 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 library 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 library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA 02111-1307  USA
 */
package alma.ACS.MasterComponentImpl.statemachine;

import java.util.logging.Logger;

import junit.framework.TestCase;

import alma.ACS.MasterComponentImpl.StateChangeSemaphore;
import alma.ACSErrTypeCommon.wrappers.AcsJIllegalStateEventEx;
import alma.acs.genfw.runtime.sm.AcsState;
import alma.acs.genfw.runtime.sm.AcsStateActionException;
import alma.acs.genfw.runtime.sm.AcsStateChangeListener;
import alma.acs.genfw.runtime.sm.AcsStateUtil;


/**
 * Tests the state machine from <code>alma.ACS.MasterComponentImpl.statemachine</code>
 * without the Master component on top of it. No running ACS needed.
 *  
 * @author hsommer
 * created Mar 3, 2004 3:27:56 PM
 */
public class StateMachineTest extends TestCase implements AcsStateChangeListener
{
    private AlmaSubsystemContext m_context;
    private DummyActionImpl m_actionImpl;
	private Logger m_logger;
	
	private MyStateChangeSemaphore m_sync;
	
	
    public void setUp() {
    	m_logger = Logger.getLogger("StateMachineTest");
    	m_actionImpl = new DummyActionImpl(m_logger);
        m_context = new AlmaSubsystemContext(m_actionImpl, m_logger);
        m_context.addAcsStateChangeListener(this);
        
        m_sync = new MyStateChangeSemaphore();
        m_context.addAcsStateChangeListener(m_sync);
    }

	/**
	 * @see alma.ACS.MasterComponentImpl.statemachine.AcsStateChangeListener#stateChangedNotify(alma.ACS.MasterComponentImpl.statemachine.AcsState[], alma.ACS.MasterComponentImpl.statemachine.AcsState[])
	 */
	public void stateChangedNotify(AcsState[] oldStateHierarchy, AcsState[] currentStateHierarchy) 
	{
		String oldHi = AcsStateUtil.stateHierarchyToString(oldStateHierarchy);
		String newHi = AcsStateUtil.stateHierarchyToString(currentStateHierarchy);
		m_logger.info("state machine switched from " + oldHi + " to " + newHi);
	}

	
    public void testLegalLifecycle() throws Exception 
	{
    	final int n = 20;
        m_logger.info("============ starting testLegalLifecycle with " + n + " iterations ===========");
    	
    	for (int i=0; i< n; i++) {
	        assertStateHierarchy("AVAILABLE/OFFLINE/SHUTDOWN");
	        m_logger.info("---> Event initPass1 will be sent.");
	        m_sync.reset();
	        m_context.initPass1();
	        m_sync.waitForStateChanges(2); 
	        assertStateHierarchy("AVAILABLE/OFFLINE/PREINITIALIZED");
	        
	        m_logger.info("---> Event initPass2 will be sent.");
	        m_sync.reset();
	        m_context.initPass2();
	        m_sync.waitForStateChanges(2); 
	        assertStateHierarchy("AVAILABLE/ONLINE");
	        
	        m_logger.info("---> Event start will be sent.");
	        m_context.start();
	        assertStateHierarchy("AVAILABLE/OPERATIONAL");
	        m_logger.info("---> Event start will be sent again.");
	        m_context.start();
	        assertStateHierarchy("AVAILABLE/OPERATIONAL");
	        m_logger.info("---> Event stop will be sent.");
	        m_context.stop();
	        assertStateHierarchy("AVAILABLE/ONLINE");
	        
	        m_logger.info("---> Event shutdownPass1 will be sent.");
	        m_sync.reset();
	        m_context.shutdownPass1();
	        m_sync.waitForStateChanges(2); 
	        assertStateHierarchy("AVAILABLE/OFFLINE/PRESHUTDOWN");
	        
	        m_logger.info("---> Event shutdownPass2 will be sent.");
	        m_sync.reset();
	        m_context.shutdownPass2();
	        m_sync.waitForStateChanges(2); 
	        assertStateHierarchy("AVAILABLE/OFFLINE/SHUTDOWN");
    	}        
        m_logger.info("============ testLegalLifecycle successful! ===========\n");
    }

    
    public void testIllegalEvent() throws Exception {
        m_logger.info("============ starting testIllegalEvent ===========");

        m_sync.reset();
        m_context.initPass1();
        m_sync.waitForStateChanges(2);
        assertStateHierarchy("AVAILABLE/OFFLINE/PREINITIALIZED");
        
        try {
        	// illegal event "start" in "AVAILABLE/OFFLINE/PREINITIALIZED"
			m_context.start();
			fail("AcsStateIllegalEventException expected!");
		}
		catch (AcsJIllegalStateEventEx e) {
			assertEquals("OFFLINE", e.getState());
			assertEquals("start", e.getEvent());
		}
        assertStateHierarchy("AVAILABLE/OFFLINE/PREINITIALIZED");
		
        m_logger.info("============ testIllegalEvent successful! ===========\n");
    }

    
    public void testActionException() throws Exception 
    {
        m_logger.info("============ starting testActionException ===========");

        m_actionImpl.throwExInInitPass1(true); // we enforce the exception    	

        m_sync.reset();
        m_context.initPass1();
        m_sync.waitForStateChanges(2); 
        assertStateHierarchy("AVAILABLE/ERROR");
        
        try {
			m_context.initPass2();
			fail("AcsJIllegalStateEventEx expected, with state machine in ERROR state");
		}
		catch (AcsJIllegalStateEventEx e) {
			assertEquals("initPass2", e.getEvent());
			assertEquals("ERROR", e.getState());
		}
        // let's get out of error again...
        m_context.shutdownPass1();
        m_sync.waitForStateChanges(2); 
        assertStateHierarchy("AVAILABLE/OFFLINE/PRESHUTDOWN");

        m_context.shutdownPass2();
        m_sync.waitForStateChanges(2); 
        assertStateHierarchy("AVAILABLE/OFFLINE/SHUTDOWN");
        
        m_logger.info("============ testActionException successful! ===========\n");
    }

    
    private void assertStateHierarchy(String expectedPath) {
		AcsState[] actualHierarchy = m_context.getCurrentTopLevelState().getStateHierarchy();
		String actualPath = AcsStateUtil.stateHierarchyToString(actualHierarchy);
		assertEquals("current state is not as expected!", expectedPath, actualPath);
    }


    /**
     * Test implementation of the state machine's action interface.
     * Methods will be called by the state machine.
     */
    private static class DummyActionImpl implements AlmaSubsystemActions 
	{
    	private Logger m_actionLogger;
		private boolean m_throwExInInitPass1;
    	
    	DummyActionImpl(Logger logger) {
    		m_actionLogger = logger;
    		m_throwExInInitPass1 = false;
    	}
    	
    	/**
    	 * Determines the optional test feature of letting {@link #initSubsysPass1()} 
    	 * throw an exception.
    	 */
    	void throwExInInitPass1(boolean throwEx) {
    		m_throwExInInitPass1 = throwEx;
    	}

    	
        public synchronized void initSubsysPass1() throws AcsStateActionException {
            if (m_throwExInInitPass1) {
                log("initSubsysPass1 (will throw AcsStateActionException)");  
                throw new AcsStateActionException("sorry, just a test: initPass1 failed!");          	
            }
            else {
            	log("initSubsysPass1");
            }            
        }

        public synchronized void initSubsysPass2() {
           	log("initSubsysPass2");
           	try {
				Thread.sleep(100);
			}
			catch (InterruptedException e) {
				e.printStackTrace();
			}
        }

        public synchronized void reinitSubsystem() {
            log("reinitSubsystem");
        }

        public synchronized void shutDownSubsysPass1() {
            log("shutDownSubsysPass1");
        }

        public synchronized void shutDownSubsysPass2() {
            log("shutDownSubsysPass2");
        }
{'fraction_non_alphanumeric': 0.10732739836892237, 'fraction_numerical': 0.00927597584510988, 'mean_word_length': 2.9247495724407524, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7255193', 'n_tokens_mistral': 4812, 'n_tokens_neox': 4533, 'n_words': 1126}