<commit_before>/*
 *    ALMA - Atacama Large Millimiter Array
 *    (c) European Southern Observatory, 2004
 *    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;

import alma.ACS.MasterComponent;
import alma.ACS.ROstringSeq;
import alma.ACS.SUBSYSSTATE_AVAILABLE;
import alma.ACS.SUBSYSSTATE_INITIALIZING_PASS1;
import alma.ACS.SUBSYSSTATE_OFFLINE;
import alma.ACS.SUBSYSSTATE_ONLINE;
import alma.ACS.SUBSYSSTATE_OPERATIONAL;
import alma.ACS.SUBSYSSTATE_PREINITIALIZED;
import alma.ACS.SUBSYSSTATE_PRESHUTDOWN;
import alma.ACS.SUBSYSSTATE_SHUTDOWN;
import alma.ACS.MasterComponentPackage.SubsystemStateEvent;
import alma.ACSErr.ACSErrTypeOK;
import alma.ACSErr.CompletionHolder;
import alma.ACSErrTypeCommon.IllegalStateEventEx;
import alma.ACSErrTypeOK.ACSErrOK;
import alma.acs.component.client.ComponentClientTestCase;
import alma.acs.exceptions.AcsJCompletion;
import alma.acs.genfw.runtime.sm.AcsStateUtil;

/**
 * @author hsommer
 * created Apr 13, 2004 4:32:51 PM
 */
public class MasterComponentTest extends ComponentClientTestCase
{
	private MasterComponent m_masterComp;

	/**
	 * Constructor for MasterComponentTest.
	 */
	public MasterComponentTest() throws Exception {		
			super("MASTERCOMP1-Test");
	}

	protected void setUp() throws Exception {
		super.setUp();
		
		org.omg.CORBA.Object compObj = getContainerServices().getComponent("MASTERCOMP1");		
		assertNotNull(compObj);
		m_masterComp = alma.ACS.MasterComponentHelper.narrow(compObj);
		assertNotNull(m_masterComp);
		
//		MasterComponentReadOnly maCompRO = alma.ACS.MasterComponentReadOnlyHelper.narrow(compObj);
//		assertNotNull(maCompRO);
	}

	protected void tearDown() throws Exception
	{
		// will release MASTERCOMP1 
		super.tearDown();
	}

	
	public void testInitPass1() throws Exception 
	{
		ROstringSeq statesProperty = m_masterComp.currentStateHierarchy(); 
		assertNotNull(statesProperty);

		// verify initial state
		String[] expectedHierarchy = new String[] {
				SUBSYSSTATE_AVAILABLE.value, SUBSYSSTATE_OFFLINE.value, SUBSYSSTATE_SHUTDOWN.value };
		verifyCurrentState(statesProperty, expectedHierarchy);
		
		// send event
		m_masterComp.doTransition(SubsystemStateEvent.SUBSYSEVENT_INITPASS1);
		
		// verify transient state (available for 1 second thanks to a sleepy test component action)
		expectedHierarchy[2] = SUBSYSSTATE_INITIALIZING_PASS1.value;
		verifyCurrentState(statesProperty, expectedHierarchy);
		
		// verify new state 
		Thread.sleep(3000);
		expectedHierarchy[2] = SUBSYSSTATE_PREINITIALIZED.value;
		verifyCurrentState(statesProperty, expectedHierarchy);
		
		// verify correct error for illegal event
		try {
			m_masterComp.doTransition(SubsystemStateEvent.SUBSYSEVENT_STOP);
			fail("expected IllegalStateEventEx");
		}
		catch (IllegalStateEventEx e) {
//			assertEquals("xyz", e.errorTrace.shortDescription);
			m_logger.info("got IllegalStateEventEx as expected.");
		}
		catch (Exception e) {
			fail("expected IllegalStateEventEx, but not this one: " + e.toString());
		}

	}

	public void testFullLifecycle() throws Exception 
	{
		ROstringSeq statesProperty = m_masterComp.currentStateHierarchy();
		assertNotNull(statesProperty);

		// verify initial state
		String[] expectedHierarchy = new String[] {
				SUBSYSSTATE_AVAILABLE.value, SUBSYSSTATE_OFFLINE.value, SUBSYSSTATE_SHUTDOWN.value };
		verifyCurrentState(statesProperty, expectedHierarchy);
		
		m_masterComp.doTransition(SubsystemStateEvent.SUBSYSEVENT_INITPASS1);
		// component-side action method initSubsysPass1 will sleep 1000 ms, during which component is in state SUBSYSSTATE_INITIALIZING_PASS1
		// thus after 1500 ms we should have reached SUBSYSSTATE_PREINITIALIZED and can send the next event
		Thread.sleep(1500);
		
		m_masterComp.doTransition(SubsystemStateEvent.SUBSYSEVENT_INITPASS2);
		// the action method initSubsysPass2 does not do anything, so we should rather quickly go via SUBSYSSTATE_INITIALIZING_PASS2 to SUBSYSSTATE_ONLINE
		Thread.sleep(500);
		expectedHierarchy = new String[] {
				SUBSYSSTATE_AVAILABLE.value, SUBSYSSTATE_ONLINE.value };
		verifyCurrentState(statesProperty, expectedHierarchy);
		
		// todo: send more events
	}

	
	
	/**
	 * Test method for multiple runs of {@link #_testEventSync()}.
	 */
	public void testEventSyncMultipleRuns() throws Exception {
		
		ROstringSeq statesProperty = m_masterComp.currentStateHierarchy();
		assertNotNull(statesProperty);

		StateChangeListener listener = new StateChangeListener(m_logger);		
		listener.createMonitor(statesProperty, getContainerServices());

		for (int i=0; i < 100; i++) {
			m_logger.info("\n*** testEventSyncMultipleRuns(" + i + ") ***");
			_testEventSync(listener);	
		}
		
		listener.destroyMonitor();
	}

	/**
	 * Uses state change notification to synchronize sending the next event,
	 * instead of stupid Thread.sleep like the above tests.
	 * <p>
	 * This method could be taken as an example of how subsystems can use these synchronization helper classes 
	 * to write unit tests for their own master components.
	 */
	private void _testEventSync(StateChangeListener listener) throws Exception 
	{
		String[] expectedHierarchy = new String[] {
				SUBSYSSTATE_AVAILABLE.value, SUBSYSSTATE_OFFLINE.value, SUBSYSSTATE_SHUTDOWN.value };
		listener.verifyCurrentState(expectedHierarchy);
		
		StateChangeSemaphore sync = listener.getStateChangeSemaphore();		
		sync.reset();<commit_msg>Added a sleep as workaround for lack of sync'ing. This should fix the year-long rare but recurring test failures from getting a state change notification too many because the initial state "shutdown" is sometimes sent as a slightly delayed notification when it is no longer expected.<commit_after>/*
 *    ALMA - Atacama Large Millimiter Array
 *    (c) European Southern Observatory, 2004
 *    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;

import alma.ACS.MasterComponent;
import alma.ACS.ROstringSeq;
import alma.ACS.SUBSYSSTATE_AVAILABLE;
import alma.ACS.SUBSYSSTATE_INITIALIZING_PASS1;
import alma.ACS.SUBSYSSTATE_OFFLINE;
import alma.ACS.SUBSYSSTATE_ONLINE;
import alma.ACS.SUBSYSSTATE_OPERATIONAL;
import alma.ACS.SUBSYSSTATE_PREINITIALIZED;
import alma.ACS.SUBSYSSTATE_PRESHUTDOWN;
import alma.ACS.SUBSYSSTATE_SHUTDOWN;
import alma.ACS.MasterComponentPackage.SubsystemStateEvent;
import alma.ACSErr.ACSErrTypeOK;
import alma.ACSErr.CompletionHolder;
import alma.ACSErrTypeCommon.IllegalStateEventEx;
import alma.ACSErrTypeOK.ACSErrOK;
import alma.acs.component.client.ComponentClientTestCase;
import alma.acs.exceptions.AcsJCompletion;
import alma.acs.genfw.runtime.sm.AcsStateUtil;

/**
 * @author hsommer
 * created Apr 13, 2004 4:32:51 PM
 */
public class MasterComponentTest extends ComponentClientTestCase
{
	private MasterComponent m_masterComp;

	/**
	 * Constructor for MasterComponentTest.
	 */
	public MasterComponentTest() throws Exception {		
			super("MASTERCOMP1-Test");
	}

	protected void setUp() throws Exception {
		super.setUp();
		
		org.omg.CORBA.Object compObj = getContainerServices().getComponent("MASTERCOMP1");
		assertNotNull(compObj);
		m_masterComp = alma.ACS.MasterComponentHelper.narrow(compObj);
		assertNotNull(m_masterComp);
		
//		MasterComponentReadOnly maCompRO = alma.ACS.MasterComponentReadOnlyHelper.narrow(compObj);
//		assertNotNull(maCompRO);
	}

	protected void tearDown() throws Exception
	{
		// will release MASTERCOMP1 
		super.tearDown();
	}

	
	public void testInitPass1() throws Exception 
	{
		ROstringSeq statesProperty = m_masterComp.currentStateHierarchy(); 
		assertNotNull(statesProperty);

		// verify initial state
		String[] expectedHierarchy = new String[] {
				SUBSYSSTATE_AVAILABLE.value, SUBSYSSTATE_OFFLINE.value, SUBSYSSTATE_SHUTDOWN.value };
		verifyCurrentState(statesProperty, expectedHierarchy);
		
		// send event
		m_masterComp.doTransition(SubsystemStateEvent.SUBSYSEVENT_INITPASS1);
		
		// verify transient state (available for 1 second thanks to a sleepy test component action)
		expectedHierarchy[2] = SUBSYSSTATE_INITIALIZING_PASS1.value;
		verifyCurrentState(statesProperty, expectedHierarchy);
		
		// verify new state 
		Thread.sleep(3000);
		expectedHierarchy[2] = SUBSYSSTATE_PREINITIALIZED.value;
		verifyCurrentState(statesProperty, expectedHierarchy);
		
		// verify correct error for illegal event
		try {
			m_masterComp.doTransition(SubsystemStateEvent.SUBSYSEVENT_STOP);
			fail("expected IllegalStateEventEx");
		}
		catch (IllegalStateEventEx e) {
//			assertEquals("xyz", e.errorTrace.shortDescription);
			m_logger.info("got IllegalStateEventEx as expected.");
		}
		catch (Exception e) {
			fail("expected IllegalStateEventEx, but not this one: " + e.toString());
		}

	}

	public void testFullLifecycle() throws Exception 
	{
		ROstringSeq statesProperty = m_masterComp.currentStateHierarchy();
		assertNotNull(statesProperty);

		// verify initial state
		String[] expectedHierarchy = new String[] {
				SUBSYSSTATE_AVAILABLE.value, SUBSYSSTATE_OFFLINE.value, SUBSYSSTATE_SHUTDOWN.value };
		verifyCurrentState(statesProperty, expectedHierarchy);
		
		m_masterComp.doTransition(SubsystemStateEvent.SUBSYSEVENT_INITPASS1);
		// component-side action method initSubsysPass1 will sleep 1000 ms, during which component is in state SUBSYSSTATE_INITIALIZING_PASS1
		// thus after 1500 ms we should have reached SUBSYSSTATE_PREINITIALIZED and can send the next event
		Thread.sleep(1500);
		
		m_masterComp.doTransition(SubsystemStateEvent.SUBSYSEVENT_INITPASS2);
		// the action method initSubsysPass2 does not do anything, so we should rather quickly go via SUBSYSSTATE_INITIALIZING_PASS2 to SUBSYSSTATE_ONLINE
		Thread.sleep(500);
		expectedHierarchy = new String[] {
				SUBSYSSTATE_AVAILABLE.value, SUBSYSSTATE_ONLINE.value };
		verifyCurrentState(statesProperty, expectedHierarchy);
		
		// todo: send more events
	}

	
	
	/**
	 * Test method for multiple runs of {@link #_testEventSync()}.
	 */
	public void testEventSyncMultipleRuns() throws Exception {
		
		ROstringSeq statesProperty = m_masterComp.currentStateHierarchy();
		assertNotNull(statesProperty);

		StateChangeListener listener = new StateChangeListener(m_logger);
		listener.createMonitor(statesProperty, getContainerServices());

		for (int i=0; i < 100; i++) {
			m_logger.info("\n*** testEventSyncMultipleRuns(" + i + ") ***");
			_testEventSync(listener);	
		}
		
		listener.destroyMonitor();
	}

	/**
	 * Uses state change notification to synchronize sending the next event,
	 * instead of stupid Thread.sleep like the above tests.
	 * <p>
	 * This method could be taken as an example of how subsystems can use these synchronization helper classes 
	 * to write unit tests for their own master components.
	 */
	private void _testEventSync(StateChangeListener listener) throws Exception 
	{
		String[] expectedHierarchy = new String[] {
				SUBSYSSTATE_AVAILABLE.value, SUBSYSSTATE_OFFLINE.value, SUBSYSSTATE_SHUTDOWN.value };
		listener.verifyCurrentState(expectedHierarchy);
		
		StateChangeSemaphore sync = listener.getStateChangeSemaphore();
		// @TODO: At the moment it is not deterministic whether we have received already the notification 
		//        for the MC going to initial shutdown state, 
		//        or if we never get it because we registered the monitor too late (check with Matej if history is sent to new monitors...),
		//        or if we will get the shutdown state notification later, which will cause a test failure because
		//        the test assumes a clean starting state without pending notifications.
		//        As a really ugly workaround we sleep for a second, to make "sure" we got the shutdown notification if we get it at all...
		Thread.sleep(1000);
		sync.reset();
{'fraction_non_alphanumeric': 0.07945287390686898, 'fraction_numerical': 0.01076313625831527, 'mean_word_length': 4.650337837837838, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, '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': '2897534', 'n_tokens_mistral': 4256, 'n_tokens_neox': 3856, 'n_words': 1118}