/******************************************************************************* * ALMA - Atacama Large Millimeter Array * Copyright (c) ESO - European Southern Observatory, 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 alma.acs.tmcdb.compare; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.Properties; import java.util.StringTokenizer; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.commons.collections.CollectionUtils; import org.custommonkey.xmlunit.XMLTestCase; import org.jdom.Document; import org.jdom.input.SAXBuilder; import org.jdom.output.Format; import org.jdom.output.XMLOutputter; import org.omg.CORBA.ORB; import alma.acs.util.ACSPorts; import alma.cdbErrType.CDBFieldDoesNotExistEx; import alma.cdbErrType.CDBRecordDoesNotExistEx; import alma.cdbErrType.WrongCDBDataTypeEx; import com.cosylab.CDB.DAL; import com.cosylab.CDB.DAO; import com.cosylab.CDB.DAOOperations; import com.cosylab.CDB.JDAL; import com.cosylab.CDB.JDALHelper; import com.cosylab.cdb.client.CDBAccess; import com.cosylab.cdb.client.DAOProxy; /** * @author jschwarz * Compares the output from two different DAL implementations * Assuming that ACS is not running on instance 0, the following two commands should be issued before * running this test: * * hibernateCdbJDal -configName TEST0 -loadXMLCDB -memory # This should also be done with Oracle every now and then * cdbjDAL -OAport 3013 * For remote debugging: export JAVA_OPTIONS="$JAVA_OPTIONS -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8080<or some other port>" */ public class TestHighLevelNodes extends XMLTestCase { private ORB orb; private final CDBAccess xmlAccess; private final CDBAccess rdbAccess; private final Logger logger; private final JDAL xmlDAL; private final JDAL rdbDAL; private String xmlXml; private String rdbXml; public TestHighLevelNodes(String name) { super(name); String rdbIOR = "corbaloc::" + ACSPorts.getIP() + ":" + "3012/CDB"; // ACSPorts.getCDBPort() + "/CDB"; String xmlIOR = "corbaloc::" + ACSPorts.getIP() + ":" + "3013/CDB"; // ACSPorts.getCDBPort() + "/CDB"; String args[] = {}; logger = Logger.getAnonymousLogger(); Properties props = new Properties(); props.setProperty("org.omg.CORBA.ORBClass","org.jacorb.orb.ORB"); props.setProperty("org.omg.CORBA.ORBSingletonClass","org.jacorb.orb.ORBSingleton"); orb = ORB.init(args, props); xmlDAL = JDALHelper.narrow(orb.string_to_object(xmlIOR)); xmlAccess = new CDBAccess(orb,logger); xmlAccess.setDAL(xmlDAL); rdbDAL = JDALHelper.narrow(orb.string_to_object(rdbIOR)); rdbAccess = new CDBAccess(orb,logger); rdbAccess.setDAL(rdbDAL); } protected void setUp() throws Exception { super.setUp(); xmlXml = xmlDAL.get_DAO("MACI/"); rdbXml = rdbDAL.get_DAO("MACI/"); } public void testMACI_Managers() throws Exception { HashSet<String> xmlNodes = new HashSet<String>(Arrays.asList(xmlDAL.list_nodes("MACI/Managers").split(" "))); HashSet<String> rdbNodes = new HashSet<String>(Arrays.asList(rdbDAL.list_nodes("MACI/Managers").split(" "))); logger.info("XML: "+xmlNodes.toString()+"; TMCDB: "+rdbNodes.toString()); assertEquals(xmlNodes,rdbNodes); for (Iterator<String> iterator = xmlNodes.iterator(); iterator.hasNext();) { String xmlstring = "MACI/Managers/"+(String) iterator.next(); DAO xmlDao = xmlDAL.get_DAO_Servant(xmlstring); DAO rdbDao = rdbDAL.get_DAO_Servant(xmlstring); examineLoggingConfig(xmlDao,rdbDao); assertEquals(xmlDao.get_string("Startup"),rdbDao.get_string("Startup")); assertEquals(xmlDao.get_string("ServiceComponents"),rdbDao.get_string("ServiceComponents")); String sx = null; boolean xbool = true; try { sx = xmlDao.get_string("ServiceDaemons"); } catch (CDBFieldDoesNotExistEx e) { xbool = false; } String sr = null; try { sr = rdbDao.get_string("ServiceDaemons"); } catch (CDBFieldDoesNotExistEx e) { if (xbool) fail("Service Daemons: XML CDB has value: "+sx+" but TMCDB can't find the field."); continue; // Neither CDB can find it; move to next property } if (!xbool) fail("Service Daemons: TMCDB has value: "+sr+" but XML CDB can't find the field."); assertEquals(sx,sr); // TODO: Redo this once Matej's implementation is complete } } public void testMACI_Channels() throws Exception { String[] xmlNodes = xmlDAL.list_nodes("MACI/Channels").split(" "); String[] rdbNodes = rdbDAL.list_nodes("MACI/Channels").split(" "); System.out.println("list_nodes gives for XML: "+xmlNodes.length+"; and for RDB: "+rdbNodes.length); // TODO: Fix this //assertEquals(xmlNodes.length,rdbNodes.length); String[] xmlDaos = xmlDAL.list_daos("MACI/Channels").split(" "); String[] rdbDaos = rdbDAL.list_daos("MACI/Channels").split(" "); System.out.println("list_daos gives for XML: "+xmlDaos.length+"; and for RDB: "+rdbDaos.length); System.out.println("\n******** list_daos output ********"); System.out.println("**** XML CDB ****"); for (int i = 0; i < xmlDaos.length; i++) { System.out.println(xmlDaos[i]); } System.out.println("\n**** RDB CDB ****"); for (int i = 0; i < rdbDaos.length; i++) { System.out.println(rdbDaos[i]); } System.out.println("\n\n******** list_nodes output ********"); System.out.println("**** XML CDB ****"); for (int i = 0; i < xmlNodes.length; i++) { System.out.println(xmlNodes[i]); } System.out.println("\n**** RDB CDB ****"); for (int i = 0; i < rdbNodes.length; i++) { System.out.println(rdbNodes[i]); } //assertEquals(xmlDaos.length,rdbDaos.length); } public void testMACI_Containers() throws Exception { String[] xmlNodes = getSubNodes(xmlDAL, "MACI/Containers"); String[] rdbNodes = getSubNodes(rdbDAL, "MACI/Containers"); logger.info("XML: "+xmlNodes.toString()+"; TMCDB: "+rdbNodes.toString()); // assertEquals(xmlNodes,rdbNodes); for (int i = 0; i < xmlNodes.length; i++) { String xmlstring = "MACI/Containers/"+xmlNodes[i]; System.out.println(xmlstring); DAO xmlDao = xmlDAL.get_DAO_Servant(xmlstring); DAO rdbDao = rdbDAL.get_DAO_Servant(xmlstring); // check if real config, otherwice skip if (readLong(xmlDao, "LoggingConfig/minLogLevel", -1) < 0) continue; assertEquals(xmlDao.get_string("Autoload"),rdbDao.get_string("Autoload")); examineDeployInfo(xmlstring); examineLoggingConfig(xmlDao,rdbDao); assertEquals(xmlDao.get_string("ImplLang"),rdbDao.get_string("ImplLang")); assertEquals(xmlDao.get_double("Timeout"),rdbDao.get_double("Timeout")); checkEqualsBoolean("UseIFR", xmlDao, rdbDao); assertEquals(xmlDao.get_long("ManagerRetry"),rdbDao.get_long("ManagerRetry")); String str = "PingInterval"; checkLongOptionalNoDefault(str, xmlDao, rdbDao); // assertEquals(xmlDao.get_string("DALtype"),rdbDao.get_string("DALtype")); // Get rid of this attribute in XML CDB?? assertEquals(xmlDao.get_long("ServerThreads"),rdbDao.get_long("ServerThreads")); checkEqualsBoolean("Recovery",xmlDao, rdbDao); // Optional Boolean, but it works! } } public void testMACI_Components() throws Exception { String[] xmlAllNodes = retrieveComponentsList(xmlAccess); String[] rdbAllNodes = retrieveComponentsList(rdbAccess); assertEquals(xmlAllNodes.length,rdbAllNodes.length); HashSet<String> xmlNodes = new HashSet<String>(Arrays.asList(xmlAllNodes)); HashSet<String> rdbNodes = new HashSet<String>(Arrays.asList(rdbAllNodes)); logger.info("XML: "+xmlNodes.toString()+";\n TMCDB: "+rdbNodes.toString()); assertTrue(xmlNodes.equals(rdbNodes)); assertTrue(CollectionUtils.isEqualCollection(xmlNodes, rdbNodes)); for (Iterator<String> iterator = xmlNodes.iterator(); iterator.hasNext();) { String xmlstring = "MACI/Components/"+(String) iterator.next(); DAO xmlDao = xmlDAL.get_DAO_Servant(xmlstring); DAO rdbDao = rdbDAL.get_DAO_Servant(xmlstring); assertEquals(xmlDao.get_string("Code"),rdbDao.get_string("Code")); assertEquals(xmlDao.get_string("Type"),rdbDao.get_string("Type")); assertEquals(xmlDao.get_string("Container"),rdbDao.get_string("Container")); assertEquals(xmlDao.get_string("Default"),rdbDao.get_string("Default")); assertEquals(xmlDao.get_string("ImplLang"),rdbDao.get_string("ImplLang")); } } private void checkEqualsBoolean(String propName, DAO xmlDao, DAO rdbDao) throws CDBFieldDoesNotExistEx, WrongCDBDataTypeEx { String xs = xmlDao.get_string(propName); String rs = rdbDao.get_string(propName); Boolean xbool = Boolean.parseBoolean(xs); Boolean rbool = Boolean.parseBoolean(rs); try { Integer ix = Integer.parseInt(xs); xbool = ix == 1 ? true : false; } catch (NumberFormatException e) { } try { Integer ir = Integer.parseInt(rs); rbool = ir == 1 ? true : false; } catch (NumberFormatException e) { } // System.out.println("xs = "+xbool+"; rs = "+rbool); assertEquals(xbool,rbool); // Optional Boolean: XML returns "1", TMCDB returns "true" } private void checkLongOptionalNoDefault(String str, DAO xmlDao, DAO rdbDao) throws Exception { boolean noRecord = false; int xmlInt = 0; int rdbInt = 0; try { xmlInt = xmlDao.get_long(str); } catch (CDBFieldDoesNotExistEx e) { noRecord = true; } try { rdbInt = rdbDao.get_long(str); if (noRecord) fail("Property "+str+" found in TMCDB but not in XML CDB."); } catch (CDBFieldDoesNotExistEx e) { if (!noRecord) fail("Property "+str+" found in XML CDB but not in TMCDB."); } if (noRecord) return; assertEquals(xmlInt,rdbInt); } private void examineDeployInfo(String xmlstring) throws Exception { boolean noRecordXml = false; DAO xmlDao = null; DAO rdbDao = null; try { xmlDao = xmlDAL.get_DAO_Servant(xmlstring+"/DeployInfo"); } catch (CDBRecordDoesNotExistEx ex) { noRecordXml = true; } try { rdbDao = rdbDAL.get_DAO_Servant(xmlstring+"/DeployInfo"); if (noRecordXml) fail("DeployInfo found for TMCDB in "+xmlstring+" but not in XML CDB"); } catch (CDBRecordDoesNotExistEx ex) { if (!noRecordXml) fail("DeployInfo found for XML CDB in "+xmlstring+" but not in TMCDB"); } if (noRecordXml) return; final String[] propertyName = {"TypeModifiers","Host","Flags","KeepAliveTime"}; //TODO: KeepAliveTime is an integer! for (int i = 0; i < propertyName.length; i++) { System.out.println(propertyName[i]); String sx = null; boolean xbool = true; try { sx = xmlDao.get_string(propertyName[i]); } catch (CDBFieldDoesNotExistEx e) { xbool = false; } String sr = null; try { sr = rdbDao.get_string(propertyName[i]); } catch (CDBFieldDoesNotExistEx e) { if (xbool) fail("XML CDB has value: "+sx+" but TMCDB can't find the field."); continue; // Neither CDB can find it; move to next property } if (!xbool) fail("TMCDB has value: "+sr+" but XML CDB can't find the field."); assertEquals(sx,sr); } checkEqualsBoolean("StartOnDemand", xmlDao, rdbDao); } private void examineLoggingConfig(DAO xmlDao, DAO rdbDao) throws Exception { assertEquals(xmlDao.get_string("LoggingConfig/centralizedLogger"),rdbDao.get_string("LoggingConfig/centralizedLogger")); assertEquals(xmlDao.get_long("LoggingConfig/dispatchPacketSize"),rdbDao.get_long("LoggingConfig/dispatchPacketSize")); assertEquals(xmlDao.get_long("LoggingConfig/immediateDispatchLevel"),rdbDao.get_long("LoggingConfig/immediateDispatchLevel")); assertEquals(xmlDao.get_long("LoggingConfig/flushPeriodSeconds"),rdbDao.get_long("LoggingConfig/flushPeriodSeconds")); assertEquals(xmlDao.get_long("LoggingConfig/maxLogQueueSize"),rdbDao.get_long("LoggingConfig/maxLogQueueSize")); assertEquals(xmlDao.get_long("LoggingConfig/maxLogsPerSecond"),rdbDao.get_long("LoggingConfig/maxLogsPerSecond")); //TODO: Handle NamedLogger, UnnamedLogger } public void testXmlMACI() throws Exception { logger.info("MACI XML string -- Classic: "+xmlXml); SAXBuilder sb = new SAXBuilder(); InputStream is = new ByteArrayInputStream(rdbXml.getBytes("UTF-8")); Document doc = sb.build(is); XMLOutputter xout = new XMLOutputter(Format.getPrettyFormat()); ByteArrayOutputStream out = new ByteArrayOutputStream(); xout.output(doc, out); logger.info("MACI XML string -- RDB: "+out.toString()); assertXMLEqual("MACI XML pieces are similar ",xmlXml ,rdbXml); // This fails at the moment because XML returns namespace info, TMCDB doesn't } private String[] getSubNodes(DAL dal, String subnode) throws Exception { ArrayList<String> subnodes = new ArrayList<String>(); LinkedList<String> stack = new LinkedList<String>(); stack.addLast(subnode); while (!stack.isEmpty()) { String parentNode = stack.removeLast().toString(); String nodes = dal.list_nodes(parentNode); if (nodes.length() > 0) { StringTokenizer tokenizer = new StringTokenizer(nodes); while (tokenizer.hasMoreTokens()) { String nodeName = tokenizer.nextToken(); if (nodeName.endsWith(".xml")) continue; String fullName = parentNode + "/" + nodeName; stack.addLast(fullName); // strip off relative path subnodes.add(fullName.substring(subnode.length()+1)); } } } String[] retVal = new String[subnodes.size()]; subnodes.toArray(retVal); return retVal; } private static final int readLong(DAOOperations dao, String name, int defaultValue) { try { return dao.get_long(name); } catch (Throwable th) { return defaultValue; } } /** * Searches dao for all potential (nodes containing Name attribute) ComponentInfo nodes. * @param dc dao to be searched. * @returns list of all potential ComponentInfo nodes. */ private String[] retrieveComponentsList(CDBAccess cdbAccess) { ArrayList<String> componentList = new ArrayList<String>(); try { DAOProxy dc = cdbAccess.createDAO("MACI/Components"); LinkedHashSet<String> nodes = new LinkedHashSet<String>(); // current nodes.add(""); String[] subnodes = cdbAccess.getSubNodes(dc); if (subnodes != null) for (int i = 0; i < subnodes.length; i++) nodes.add(subnodes[i]); Iterator<String> iter = nodes.iterator(); while (iter.hasNext()) { String prefix = iter.next().toString(); if (prefix.length() > 0) prefix += "/"; String attributes = dc.get_field_data(prefix + "_characteristics"); // convert into array StringTokenizer tokenizer = new StringTokenizer(attributes, ","); while (tokenizer.hasMoreTokens()) { String subname = tokenizer.nextToken().toString(); String componentName = prefix + subname; // check if potentially valid ComponentInfo entry - read name /// @todo this could be done better (to check if all attributes exist) if (readStringCharacteristics(dc, componentName + "/Name", true) != null) componentList.add(componentName); } } } catch (Throwable th) { Exception ce = new Exception("Failed to obtain list of all components.", th); logger.log(Level.WARNING, ce.getMessage(), ce); } String[] retVal = new String[componentList.size()]; componentList.toArray(retVal); //logger.log(Level.INFO,"Found " + retVal.length + " component entries in the configuration database."); return retVal; } /** * Reads DAO (CDB access) of string type. * * @param path path to be read non-<code>null</code>. * @param dao DAO on which to perform read request. * @param silent do not complain, if characteristics not found * @return String value read, <code>null</code> on failure * @throws Exception */ private String readStringCharacteristics(DAOProxy dao, String path, boolean silent) throws Exception { assert (path != null); String retVal = null; try { retVal = dao.get_string(path); } catch (Throwable th) { Exception ce = new Exception("Failed to read '"+path+"' field on DAO dao '"+dao+"'.", th); if (!silent) throw ce; } return retVal; } protected void tearDown() throws Exception { super.tearDown(); } }