/*
* 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
*
*/
/**
* @author almadev
* @version $Id: SendTest.java,v 1.12 2012/10/22 11:46:37 hsommer Exp $
* @since
*/
package alma.lasersource.test;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.Iterator;
import java.util.Properties;
import java.util.logging.Level;
import cern.laser.source.alarmsysteminterface.FaultState;
import cern.laser.source.alarmsysteminterface.impl.ASIMessageHelper;
import cern.laser.source.alarmsysteminterface.impl.FaultStateImpl;
import cern.laser.source.alarmsysteminterface.impl.XMLMessageHelper;
import cern.laser.source.alarmsysteminterface.impl.message.ASIMessage;
import com.cosylab.acs.jms.ACSJMSMessageEntity;
import alma.acs.component.client.ComponentClientTestCase;
import alma.acs.container.ContainerServices;
import alma.acs.nc.AcsEventSubscriber;
import alma.acscommon.ACS_NC_DOMAIN_ALARMSYSTEM;
import alma.acsnc.EventDescription;
import alma.alarmsystem.source.ACSAlarmSystemInterface;
import alma.alarmsystem.source.ACSAlarmSystemInterfaceFactory;
import alma.alarmsystem.source.ACSFaultState;
/**
* A class to test the sources.
* It is composed of 2 tests:
* 1- send an alarm
* 2- stress test that sends several alarms
*
* Each message is checked for integrity
*
*/
public class SendTest extends ComponentClientTestCase implements AcsEventSubscriber.Callback<ACSJMSMessageEntity> {
public SendTest() throws Exception {
super("SendTest");
}
private volatile AcsEventSubscriber<ACSJMSMessageEntity> m_consumer;
private static final String m_channelName = "CMW.ALARM_SYSTEM.ALARMS.SOURCES.ALARM_SYSTEM_SOURCES";
// private ContainerServices m_contSvcs;
private final int ITERATIONS = 10;
// The number of the message received
// Each FS has the FM and FM containing that number and the FC=num of msg
// In this way we can check the integrity
private int nMsgReceived;
/**
* Alarm NC events are received in different threads than the tests run in.
* In order to let the test fail when there are receiver exceptions or validation errors, we can
* communicate them in this variable.
*/
private volatile Object receiverError;
// The FM and FF of a FaultState are composed of the following String
// with the num of the message appended
private String faultFamily="AlarmSource";
private String faultMember ="ALARM_SOURCE_ANTENNA";
public void setUp() throws Exception {
super.setUp();
nMsgReceived=0;
try {
final ContainerServices contSvcs = getContainerServices();
assertNotNull("Error getting the ContainerServices",contSvcs);
// Check if the CERN AS is in use
assertFalse("Using ACS implementation instead of CERN", ACSAlarmSystemInterfaceFactory.usingACSAlarmSystem());
m_logger.info("alarm system initialized.");
m_consumer = getContainerServices().createNotificationChannelSubscriber(
m_channelName, ACS_NC_DOMAIN_ALARMSYSTEM.value, ACSJMSMessageEntity.class);
m_consumer.addSubscription(this);
m_consumer.startReceivingEvents();
m_logger.info("NC consumer installed on channel " + m_channelName);
} catch (Exception ex) {
super.tearDown();
throw ex;
}
}
public void tearDown() throws Exception {
m_logger.info("tearDown called.");
m_consumer.disconnect();
m_logger.info("tearDown: done clearing NC consumer and alarm factory.");
super.tearDown();
}
// Send one message to check if the message received
// from the NC is coherent
public void testSend() throws Exception {
m_logger.info("testSend() will send a single alarm message.");
int faultCode=0;
String descriptor=ACSFaultState.ACTIVE;
ACSAlarmSystemInterface alarmSource;
try {
alarmSource = ACSAlarmSystemInterfaceFactory.createSource();
assertNotNull("Error instantiating the source",alarmSource);
ACSFaultState fs = ACSAlarmSystemInterfaceFactory.createFaultState(
faultFamily+"0", faultMember+"0", faultCode);
assertNotNull("Error instantiating the FS",fs);
fs.setDescriptor(descriptor);
fs.setUserTimestamp(new Timestamp(System.currentTimeMillis()));
Properties props = new Properties();
props.setProperty(ACSFaultState.ASI_PREFIX_PROPERTY, "prefix");
props.setProperty(ACSFaultState.ASI_SUFFIX_PROPERTY, "suffix");
fs.setUserProperties(props);
m_logger.info("alarm message is prepared and will be sent now. Then test will wait for 10 seconds.");
alarmSource.push(fs);
try {
Thread.sleep(10000);
} catch (Exception e) {}
} catch (Exception e) {
m_logger.log(Level.INFO, "Exception caught while pushing the alarm", e);
throw e;
}
finally {
assertNull(receiverError);
}
}
// Send 20K alarms
public void testStress() throws Exception {
ACSAlarmSystemInterface alarmSource;
try {
alarmSource = ACSAlarmSystemInterfaceFactory.createSource();
assertNotNull("Error instantiating the source",alarmSource);
ACSFaultState[] faultStates = new ACSFaultState[ITERATIONS];
for (int t=0; t<ITERATIONS; t++) {
faultStates[t]= ACSAlarmSystemInterfaceFactory.createFaultState(
faultFamily+t, faultMember+t, t);
assertNotNull("Error instantiating a fault state",faultStates[t]);
if (t%2==0) {
faultStates[t].setDescriptor(ACSFaultState.ACTIVE);
} else {
faultStates[t].setDescriptor(ACSFaultState.TERMINATE);
}
Properties props = new Properties();
props.setProperty(ACSFaultState.ASI_PREFIX_PROPERTY, "prefix");
props.setProperty(ACSFaultState.ASI_SUFFIX_PROPERTY, "suffix");
faultStates[t].setUserProperties(props);
faultStates[t].setUserTimestamp(new Timestamp(System.currentTimeMillis()));
}
m_logger.info("all alarm messages are prepared.");
for (int t=0; t<ITERATIONS; t++) {
m_logger.info("alarm message #" + t + " will be sent now.");
alarmSource.push(faultStates[t]);
try {
Thread.sleep(10); // HSO: if alarm system needs 10 ms sleep, then this should be enforced in the alarm classes, not in the test!
} catch (Exception e) {}
}
try {
Thread.sleep(10000);
} catch (Exception e) {}
} catch (Exception e) {
System.out.println("Exception caught while pushing"+e.getMessage());
System.out.println("Cause: "+e.getCause());
e.printStackTrace();
throw e;
}
finally {
assertNull(receiverError);
}
}
/**
* The method receives all the messages published in the NC
* For each message received it checks if its content is right
* i.e. the name of the class, the member and the code contains the
* number of the message in the sequence. In this way it also checks
* if the messages are received in the same order they were sent.
* The method also checks if all the messages have been received
* and prints a message if receives more messages then the messages
* pushed
*
* @param msg The message received from the NC
* @see alma.acs.nc.Consumer
*/
@Override
public synchronized void receive(ACSJMSMessageEntity msg, EventDescription eventDescrip) {
Collection<FaultState> faultStates;
try {
ASIMessage asiMsg = XMLMessageHelper.unmarshal(msg.text);
faultStates = ASIMessageHelper.unmarshal(asiMsg);
} catch (Exception e) {
System.out.println("Exception caught while unmarshalling the msg "+e.getMessage());
e.printStackTrace();
receiverError = e;
return;
}
Iterator<FaultState> iter = faultStates.iterator();
while (iter.hasNext()) {
FaultStateImpl fs = (FaultStateImpl)iter.next();
if (!isValidFSMessage(fs,nMsgReceived)) {
receiverError = "Invalid FaultState received as #" + nMsgReceived;
}
nMsgReceived++;
if (nMsgReceived==ITERATIONS) {
System.out.println("All alarms sent and received");
} else if (nMsgReceived>ITERATIONS) {
System.out.println("Received an alarm that has never been sent");
}
}
}
@Override
public Class<ACSJMSMessageEntity> getEventType() {
return ACSJMSMessageEntity.class;
}
/**
* Check if the message is coherent with the number
*
* @param fs The FS to check
* @param num The number of the message
*
* @return true if the message is right
*/
private boolean isValidFSMessage(FaultStateImpl fs, int num) {
boolean res = fs.getFamily().equals(faultFamily+num);
res = res && fs.getMember().equals(faultMember+num);
res = res && fs.getCode()==num;
return res;
}
}