/*******************************************************************************
* ALMA - Atacama Large Millimeter Array
* Copyright (c) COSYLAB - Control System Laboratory, 2011
* (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 com.cosylab.logging.engine.ACS;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Vector;
import org.xml.sax.helpers.ParserFactory;
import junit.framework.TestCase;
import alma.acs.logging.engine.parser.ACSLogParser;
import alma.acs.logging.engine.parser.ACSLogParserFactory;
import alma.acs.logging.engine.parser.ACSLogParserFactory.ParserTypes;
import alma.acs.util.IsoDateFormat;
import com.cosylab.logging.engine.log.ILogEntry;
import com.cosylab.logging.engine.log.LogTypeHelper;
import com.cosylab.logging.engine.log.ILogEntry.AdditionalData;
import com.cosylab.logging.engine.log.LogField;
/**
* The class to test parsing.
* <P>
* The tests iterate over all possible parsers.
*
* @author acaproni
*
*/
public class ACSLogParserTest extends TestCase {
private ACSLogParser parser;
private final String xmlLogInfo1 =
"<Info TimeStamp=\"2006-03-28T00:26:29.238\" File=\"maciContainerImpl.cpp\" Line=\"1454\" " +
"Routine=\"maci::ContainerImpl::initThread\" Host=\"gas\" Process=\"maciContainer\" Thread=\"ARCHIVE_BULKSENDER::actionThread\" " +
"Context=\"CTXT\" SourceObject=\"ARCHIVE_BULKSENDER::source\" Audience=\"Operator\" Array=\"AnArray\" Antenna=\"ThisIsTheAntenna\""+
" StackLevel=\"10\" StackId=\"TheStackID\" Priority=\"3\">" +
"<![CDATA[Thread name: 'ARCHIVE_BULKSENDER::actionThread']]>" +
"</Info>";
private final String xmlLogInfo2 =
"<Info TimeStamp=\"2006-03-28T00:26:29.239\" File=\"maciContainerImpl.cpp\" Line=\"1454\" " +
"Routine=\"maci::ContainerImpl::initThread\" Host=\"gas\" Process=\"maciContainer\" Thread=\"ARCHIVE_BULKSENDER::monitorThread\" " +
"Context=\"\" SourceObject=\"ARCHIVE_BULKSENDER::monitorThread\">" +
"<![CDATA[Thread name: 'ARCHIVE_BULKSENDER::monitorThread']]>" +
"</Info>";
private final String xmlLogWarningWithException =
"<Warning TimeStamp=\"2006-03-28T00:26:46.149\" " +
"File=\"alma.acs.container.ContainerSealant\" Line=\"184\" Routine=\"invoke\" Host=\"gas\" " +
"Process=\"LoggerName: alma.acs.container.ARCHIVE/ACC/javaContainer\" SourceObject=\"ARCHIVE/ACC/javaContainer\" " +
"Thread=\"RequestProcessor-15\" StackId=\"unknown\" StackLevel=\"0\" LogId=\"298\">" +
"<![CDATA[checked exception was thrown in functional method 'ARCHIVE_CONNECTION/alma.xmlstore.Operational#retrieve':]]>" +
"<Data Name=\"LoggedException\"><![CDATA[alma.xmlstore.OperationalPackage.NotFound: uid://X00000000000028aa/X00000002" + "\n" +
" at alma.archive.components.OperationalImpl.retrieve(OperationalImpl.java:450)" + "\n" +
" at alma.archive.components.OperationalImpl.retrieve(OperationalImpl.java:480)" + "\n" +
" at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)" + "\n" +
" at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)" + "\n" +
" at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)" + "\n" +
" at java.lang.reflect.Method.invoke(Method.java:585)" + "\n" +
" at alma.acs.container.ContainerSealant.invoke(ContainerSealant.java:155)" + "\n" +
" at $Proxy3.retrieve(Unknown Source)" + "\n" +
" at alma.xmlstore.OperationalPOATie.retrieve(OperationalPOATie.java:103)" + "\n" +
" at alma.xmlstore.OperationalPOA._invoke(OperationalPOA.java:316)" + "\n" +
" at org.jacorb.poa.RequestProcessor.invokeOperation(Unknown Source)" + "\n" +
" at org.jacorb.poa.RequestProcessor.process(Unknown Source)" + "\n" +
" at org.jacorb.poa.RequestProcessor.run(Unknown Source)" + "\n" +
"]]></Data><Data Name=\"Pippo\"><![CDATA[Pluto]]></Data></Warning>";
/**
* An array of special ogs i.e. logs that for one reason or another presented some problem while parsing.
*/
private final String[] specialLogs = {
// There was an error while parsing logs where the <DATA> appears before the body of the message
"<Info TimeStamp=\"2006-03-28T00:26:29.239\">" +
"<Data Name=\"Pippo\"><![CDATA[Pluto]]></Data>" +
"<Data Name=\"2ndName\"><![CDATA[2ndVal]]></Data>" +
"<![CDATA[Thread name: 'ARCHIVE_BULKSENDER::monitorThread']]>" +
"</Info>"
};
/**
* Parses one log record from XML and verifies a few fields,
* including the exception details that are attached as additional data.
*
* @throws Exception
*/
public void testParseLogRecord() throws Exception {
// Cycle through all available parsers
for (ParserTypes type: ParserTypes.values()) {
System.out.println("testParseLogRecord: Testing parser "+type);
parser = ACSLogParserFactory.getParser(type);
assertNotNull(parser);
assertEquals(type, ACSLogParserFactory.getParserType(parser));
ILogEntry log = parser.parse(xmlLogWarningWithException);
// verify some fields
assertEquals("wrong typename string", "Warning", ((LogTypeHelper)log.getField(LogField.ENTRYTYPE)).logEntryType);
assertEquals("wrong type code", LogTypeHelper.WARNING, ((LogTypeHelper)log.getField(LogField.ENTRYTYPE)));
Vector<ILogEntry.AdditionalData> additionalData = log.getAdditionalData();
assertFalse("There should have been 2 pieces of additional data!", additionalData == null || additionalData.size() != 2);
// Check the first data
ILogEntry.AdditionalData myData = additionalData.get(0);
assertEquals("LoggedException", myData.name);
assertTrue(myData.value.startsWith("alma.xmlstore.OperationalPackage.NotFound: uid://X00000000000028aa/X00000002"));
// Check the second data
ILogEntry.AdditionalData d = additionalData.get(1);
assertEquals("Pippo", d.name);
assertEquals("Pluto", d.value);
}
}
/**
* Check if the fields are read as expected
*
* @throws Exception
*/
public void testFields() throws Exception {
// Cycle through all available parsers
for (ParserTypes type: ParserTypes.values()) {
System.out.println("testFields: Testing parser "+type);
parser = ACSLogParserFactory.getParser(type);
assertNotNull(parser);
assertEquals(type, ACSLogParserFactory.getParserType(parser));
ILogEntry log = parser.parse(xmlLogInfo1);
assertNotNull(log);
// Check the date
Long logDate = (Long)log.getField(LogField.TIMESTAMP);
assertNotNull(logDate);
Long xmlDate=null;
SimpleDateFormat dateFormat = new IsoDateFormat();
Date date = dateFormat.parse("2006-03-28T00:26:29.238");
xmlDate = Long.valueOf(date.getTime());
assertEquals("The dates differ", xmlDate,logDate);
// Check the log type
assertEquals(LogTypeHelper.INFO,(LogTypeHelper)log.getField(LogField.ENTRYTYPE));
// Check the file
assertEquals("maciContainerImpl.cpp", log.getField(LogField.FILE));
// Check the line
assertEquals(Integer.valueOf(1454), log.getField(LogField.LINE));
// Check the routine
assertEquals("maci::ContainerImpl::initThread",log.getField(LogField.ROUTINE));
// Check the host
assertEquals("gas",log.getField(LogField.HOST));
// Check the process
assertEquals("maciContainer",log.getField(LogField.PROCESS));
// Check the thread
assertEquals("ARCHIVE_BULKSENDER::actionThread",log.getField(LogField.THREAD));
// Check the Antenna
assertEquals("CTXT", log.getField(LogField.CONTEXT));
// Check the source object
assertEquals("ARCHIVE_BULKSENDER::source",log.getField(LogField.SOURCEOBJECT));
// Check the stack level
assertEquals(10,log.getField(LogField.STACKLEVEL));
// Check the stack level
assertEquals(3,log.getField(LogField.PRIORITY));
// Check the stack level
assertEquals("TheStackID",log.getField(LogField.STACKID));
// Check the Audience
assertEquals("Operator",log.getField(LogField.AUDIENCE));
// Check the Array
assertEquals("AnArray", log.getField(LogField.ARRAY));
// Check the Antenna
assertEquals("ThisIsTheAntenna", log.getField(LogField.ANTENNA));
}
}
/**
* Call the parser several times
*
* @throws Exception
*/
public void testMultipleParse() throws Exception {
// Cycle through all available parsers
for (ParserTypes type: ParserTypes.values()) {
System.out.println("testMultipleParse: Testing parser "+type);
parser = ACSLogParserFactory.getParser(type);
assertNotNull(parser);
assertEquals(type, ACSLogParserFactory.getParserType(parser));
String[] logs = new String[3*1000];
for (int t=0; t<logs.length; t+=3) {
logs[t]=xmlLogInfo1;
logs[t+1]=xmlLogInfo2;
logs[t+2]=xmlLogWarningWithException;
}
for (String xmlLog: logs) {
ILogEntry log = parser.parse(xmlLog);
assertNotNull(log);
}
}
}
/**
* Test special logs i.e. logs that sometime have returned errors while parsing.
*
* @see <code>specialLogs</code>
* @throws Exception
*/
public void testSpecialLogs() throws Exception {
// Cycle through all available parsers
for (ParserTypes type: ParserTypes.values()) {
System.out.println("testSpecialLogs: Testing parser "+type);
parser = ACSLogParserFactory.getParser(type);
assertNotNull(parser);
assertEquals(type, ACSLogParserFactory.getParserType(parser));
for (String xmlLog: specialLogs) {
ILogEntry log = parser.parse(xmlLog);
Vector <AdditionalData> data = log.getAdditionalData();
if (data!=null) {
for (int t=0; t<data.size(); t++) {
AdditionalData d = data.get(t);
System.out.println("Data: name="+d.name+", value="+d.value);
}
} else {
System.out.println("The log has no additional data entries");
}
System.out.println("Body: "+log.getField(LogField.LOGMESSAGE));
}
}
}
}