/* * ALMA - Atacama Large Millimiter Array (c) European Southern Observatory, 2006 * * 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.lasercore.test; import java.sql.Timestamp; import java.util.HashMap; import java.util.Random; import cern.laser.source.alarmsysteminterface.FaultState; import alma.acs.component.client.ComponentClientTestCase; import alma.acs.container.ContainerServices; import alma.acs.lasercore.test.stress.CategoryClient; import alma.acs.lasercore.test.stress.category.AlarmView; import alma.acs.lasercore.test.stress.category.CategoryListener; import alma.alarmsystem.source.ACSAlarmSystemInterface; import alma.alarmsystem.source.ACSAlarmSystemInterfaceFactory; import alma.alarmsystem.source.ACSFaultState; /** * This test sends a lot of fault states and check if they are published in the * categories as expected. * To avoid defining a great number of alarms in the CDB, a default alarm * has been set in the TEST family * * Sources are not tested here because they have already been tested in laser-source * * NOTE: the test is performed without using the CategoryClient that at this level * is not available (it requires modules compiled later in the build * sequence) * * * @author acaproni * */ public class StressTest extends ComponentClientTestCase implements CategoryListener { /** * The relevant fields of a fault state to publish * * @author acaproni * */ private class MiniFaultState { // The fields of the fault state public final String FF, FM; public final int FC; public final long msec; public final String description; // ACTIVE/Terminate public final Timestamp timestamp; public MiniFaultState() { FF=StressTest.FF; //FM=StressTest.FM+Math.abs(rnd.nextInt()); FM=StressTest.FM+(count++); FC = Math.abs(rnd.nextInt() % 2) + 1; msec=System.currentTimeMillis(); timestamp=new Timestamp(msec); if (rnd.nextInt()%2==0) { description=FaultState.ACTIVE; StressTest.this.activeFS++; } else { description=FaultState.TERMINATE; } assertNotNull(FF); assertNotNull(FM); assertNotNull(description); assertNotNull(timestamp); } } /** * FF of the published states */ private static final String FF = "TEST"; /** * FM of the published states */ private static final String FM = "Member"; /** * The number of alarms to publish */ private static final int NUM_ALARMS_TO_SEND = 1000; /** * The random number generator to create FMs */ private static Random rnd = new Random(System.currentTimeMillis()); /** * The source */ private ACSAlarmSystemInterface alarmSource; /** * The category client */ private CategoryClient categoryClient; /** * The fault states to publish */ private MiniFaultState[] statesToPublish; /** * Container services */ private ContainerServices contSvcs; /** * The number of active FS published */ private int activeFS=0; /** * Used to generated the FM of the {@link MiniFaultState}'s to send. */ private static int count=0; /** * The vector with the alarms received from the categories. * The key is the alarm ID */ private HashMap<String,AlarmView> alarms = new HashMap<String,AlarmView>(); /** * Constructor * @throws Exception */ public StressTest() throws Exception { super("StressTest"); } @Override protected void setUp() throws Exception { super.setUp(); contSvcs = getContainerServices(); assertNotNull(contSvcs); alarmSource = ACSAlarmSystemInterfaceFactory.createSource(); assertNotNull("Error instantiating the source",alarmSource); // Connect the categories categoryClient= new CategoryClient(contSvcs); assertNotNull(categoryClient); categoryClient.addAlarmListener(this); categoryClient.connect(); // generate the alarms statesToPublish=new MiniFaultState[NUM_ALARMS_TO_SEND]; for (int t=0; t<statesToPublish.length; t++) { MiniFaultState mfs = new MiniFaultState(); assertNotNull(mfs); statesToPublish[t]=mfs; } } @Override protected void tearDown() throws Exception { cleanActiveAlarms(); categoryClient.disconnect(); super.tearDown(); } /** * @see {@link CategoryListener} */ @Override public void alarmReceived(AlarmView alarm) { synchronized (alarms) { if (alarm.active && alarm.alarmID.startsWith(FF+":"+FM)) { alarms.put(alarm.alarmID,alarm); } } } /** * publish a FaultState * * @param mfs The fault state to publish */ private void send(MiniFaultState mfs) throws Exception { assertNotNull(mfs); ACSFaultState fs = ACSAlarmSystemInterfaceFactory.createFaultState(mfs.FF, mfs.FM, mfs.FC); assertNotNull("Error instantiating the FS",fs); fs.setDescriptor(mfs.description); fs.setUserTimestamp(mfs.timestamp); alarmSource.push(fs); } /** * Publishes all the alarms at once then wait until all of them are published by the * alarm service. * Finally check if the received alarms match with the published fault states. * * The test is based on active alarms only and discards all the terminated ones. * All the published fault states are then compared with alarms received by the * alarm service * * <B>NOTE</B>: <em>The alarm service publishes an active alarm only if its state * changes</em> * This test works only if the set of alarms it sends is not already present in * the alarm service. * If it is not the case, the alarm published by the AS depend on the alarms * already present in the service. */ public void testStress() throws Exception { // Send the alarms for (MiniFaultState state: statesToPublish) { send(state); try { Thread.sleep(250); } catch (Exception e) {} } int timeout = 60; // timeout in secs int cnt=0; int old=0; // The number of items read in the previous iteration // Wait for all the alarms to be in the vector while (alarms.size()<activeFS && cnt<2*timeout) { if (old!=alarms.size()) { cnt=0; old=alarms.size(); } try { Thread.sleep(500); cnt++; } catch (Exception e) {} } assertEquals("Wrong number of alarms received",activeFS, alarms.size()); // Check the correctness of the alarms against the fault states for (MiniFaultState mfs: statesToPublish) { if (mfs.description.equals(FaultState.TERMINATE)) { continue; } AlarmView alarm = alarms.get(mfs.FF+":"+mfs.FM+":"+mfs.FC); assertNotNull("Alarm not published",alarm); } } /** * Clean all the active alarms published by the test. * This method must be called in the <code>cleanUp</code> in order * to terminate all the active alarms and be ready for a new test. */ private void cleanActiveAlarms() throws Exception { for (MiniFaultState mfs: statesToPublish) { if (mfs.description.equals(FaultState.ACTIVE)) { ACSFaultState fs = ACSAlarmSystemInterfaceFactory.createFaultState(mfs.FF, mfs.FM, mfs.FC); assertNotNull("Error instantiating the FS",fs); fs.setDescriptor(FaultState.TERMINATE); fs.setUserTimestamp(mfs.timestamp); alarmSource.push(fs); } } } }