/** * ************************************************************************** * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for * the specific language governing rights and limitations under the License. * * The Original Code is TEAM Engine. * * The Initial Developer of the Original Code is Northrop Grumman Corporation * jointly with The National Technology Alliance. Portions created by Northrop * Grumman Corporation are Copyright (C) 2005-2006, Northrop Grumman * Corporation. All Rights Reserved. * * Contributor(s): * S. Gianfranceschi (Intecs): Added the SOAP suport * C. Heazel (WiSC): Added Fortify adjudication changes * *************************************************************************** */ package com.occamlab.te; import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintStream; import java.io.PrintWriter; import java.io.RandomAccessFile; import java.io.StringReader; import java.io.StringWriter; import java.lang.reflect.Method; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import java.util.zip.CRC32; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import javax.xml.XMLConstants; // Addition for Fortify modifications import org.w3c.dom.Attr; import org.w3c.dom.Comment; import org.w3c.dom.Comment; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.Text; import org.xml.sax.ErrorHandler; import com.occamlab.te.index.FunctionEntry; import com.occamlab.te.index.Index; import com.occamlab.te.index.ParserEntry; import com.occamlab.te.index.ProfileEntry; import com.occamlab.te.index.SuiteEntry; import com.occamlab.te.index.TemplateEntry; import com.occamlab.te.index.TestEntry; import com.occamlab.te.saxon.ObjValue; import com.occamlab.te.util.Constants; import com.occamlab.te.util.DomUtils; import com.occamlab.te.util.IOUtils; import com.occamlab.te.util.LogUtils; import com.occamlab.te.util.Misc; import com.occamlab.te.util.SoapUtils; import com.occamlab.te.util.StringUtils; import com.occamlab.te.util.URLConnectionUtils; import net.sf.saxon.dom.NodeOverNodeInfo; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.expr.XPathContextMajor; import net.sf.saxon.instruct.Executable; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.s9api.Axis; import net.sf.saxon.s9api.QName; import net.sf.saxon.s9api.S9APIUtils; import net.sf.saxon.s9api.SaxonApiException; import net.sf.saxon.s9api.Serializer; import net.sf.saxon.s9api.XdmAtomicValue; import net.sf.saxon.s9api.XdmDestination; import net.sf.saxon.s9api.XdmItem; import net.sf.saxon.s9api.XdmNode; import net.sf.saxon.s9api.XdmNodeKind; import net.sf.saxon.s9api.XdmSequenceIterator; import net.sf.saxon.s9api.XsltExecutable; import net.sf.saxon.s9api.XsltTransformer; import net.sf.saxon.trans.XPathException; /** * Provides various utility methods to support test execution and logging. * Primary ones include implementation and execution of ctl:suite, ctl:profile, * ctl:test, ctl:function, ctl:request and ctl:soap-request instructions, and * invocation of any parsers specified therein. * */ public class TECore implements Runnable { private static final Logger LOGR = Logger.getLogger(TECore.class.getName()); public static final String SOAP_V_1_1 = "1.1"; public static final String SOAP_V_1_2 = "1.2"; Engine engine; // Engine object Index index; public static int testCount = 0; int reTestCount = 0; public static int methodCount = 0; String testName = ""; public static String nameOfTest = ""; RuntimeOptions opts; String testServletURL = null; volatile PrintStream out; // Console destination boolean web = false; // True when running as a servlet RecordedForms recordedForms; String testPath; // Uniquely identifies a test instance String fnPath = ""; // Uniquely identifies an XSL function instance within a // test instance String indent = ""; // Contains the appropriate number of spaces for the // current indent level String contextLabel = ""; // Current context label set by ctl:for-each String testType = "Mandatory"; // Type of current test String defaultResultName = "Pass"; // Default result name for current test int defaultResult = PASS; // Default result for current test ArrayList<String> media = new ArrayList<>(); public File dirPath; private int verdict; //Test verdict for current test Document prevLog = null; // Log document for current test from previous test // execution (resume and retest modes only) // Log document for suite to enable use of getLogCache by profile test Document suiteLog = null; public static String pathURL = ""; public static String assertionMsz = ""; public static String messageTest = ""; PrintWriter logger = null; // Logger for current test volatile String formHtml; // HTML representation for an active form volatile Document formResults; // Holds form results until they are // retrieved Map<String, Element> formParsers = new HashMap<String, Element>(); Map<Integer, Object> functionInstances = new HashMap<Integer, Object>(); Map<String, Object> parserInstances = new HashMap<String, Object>(); Map<String, Method> parserMethods = new HashMap<String, Method>(); LinkedList<TestEntry> testStack = new LinkedList<TestEntry>(); volatile boolean threadComplete = false; volatile boolean stop = false; volatile ByteArrayOutputStream threadOutput; public static final int CONTINUE = -1; public static final int BEST_PRACTICE = 0; public static final int PASS = 1; public static final int NOT_TESTED = 2; public static final int SKIPPED = 3; public static final int WARNING = 4; public static final int INHERITED_FAILURE = 5; public static final int FAIL = 6; public static final String MSG_CONTINUE = "Inconclusive! Continue Test"; public static final String MSG_BEST_PRACTICE = "Passed as Best Practice"; public static final String MSG_PASS = "Passed"; public static final String MSG_NOT_TESTED = "Not Tested"; public static final String MSG_SKIPPED = "Skipped - Prerequisites not satisfied"; public static final String MSG_WARNING = "Warning"; public static final String MSG_INHERITED_FAILURE = "Failed - Inherited"; public static final String MSG_FAIL = "Failed"; public static final int MANDATORY = 0; public static final int MANDATORY_IF_IMPLEMENTED = 1; public static final int OPTIONAL = 2; static final String XSL_NS = Test.XSL_NS; static final String CTL_NS = Test.CTL_NS; static final String TE_NS = Test.TE_NS; static final String INDENT = " "; static final QName TECORE_QNAME = new QName("te", TE_NS, "core"); static final QName TEPARAMS_QNAME = new QName("te", TE_NS, "params"); static final QName LOCALNAME_QNAME = new QName("local-name"); static final QName LABEL_QNAME = new QName("label"); static final String HEADER_BLOCKS = "header-blocks"; private static Logger jlogger = Logger.getLogger("com.occamlab.te.TECore"); public static DocumentBuilderFactory icFactory; public static DocumentBuilder icBuilder; public static Document doc; public static Element mainRootElement; public static DocumentBuilderFactory icFactoryClause; public static DocumentBuilder icBuilderClause; public static Document docClause; public static Element mainRootElementClause; public static String TESTNAME = ""; public static int rootNo = 0; public static String Clause = ""; public static String Purpose = ""; public static ArrayList<String> rootTestName = new ArrayList<String>(); public TECore() { } public TECore(Engine engine, Index index, RuntimeOptions opts) { this.engine = engine; this.index = index; this.opts = opts; this.recordedForms = new RecordedForms(opts.getRecordedForms()); testPath = opts.getSessionId(); out = System.out; } public TestEntry getParentTest() { if (testStack.size() < 2) { return testStack.peek(); } else { return testStack.get(1); } } public String getParamsXML(List<String> params) throws Exception { String paramsXML = "<params>"; for (int i = 0; i < params.size(); i++) { String param = params.get(i); String name = param.substring(0, param.indexOf('=')); String value = param.substring(param.indexOf('=') + 1); if (params.get(i).indexOf('=') != 0) { paramsXML += "<param local-name=\"" + name + "\" namespace-uri=\"\" prefix=\"\" type=\"xs:string\">"; paramsXML += "<value><![CDATA[" + value + "]]></value>"; paramsXML += "</param>"; } } paramsXML += "</params>"; // System.out.println("paramsXML: "+paramsXML); return paramsXML; } XPathContext getXPathContext(TestEntry test, String sourcesName, XdmNode contextNode) throws Exception { XPathContext context = null; if (test.usesContext()) { XsltExecutable xe = engine.loadExecutable(test, sourcesName); Executable ex = xe.getUnderlyingCompiledStylesheet() .getExecutable(); context = new XPathContextMajor(contextNode.getUnderlyingNode(), ex); } return context; } // Execute tests public void execute() throws Exception { try { TestEntry grandParent = new TestEntry(); grandParent.setType("Mandatory"); testStack.push(grandParent); String sessionId = opts.getSessionId(); int mode = opts.getMode(); ArrayList<String> params = opts.getParams(); if (mode == Test.RESUME_MODE) { reexecute_test(sessionId); } else if (mode == Test.REDO_FROM_CACHE_MODE) { reexecute_test(sessionId); } else if (mode == Test.RETEST_MODE) { for (String testPath : opts.getTestPaths()) { reexecute_test(testPath); } } else if (mode == Test.TEST_MODE) { String testName = opts.getTestName(); if (testName != null) { XdmNode contextNode = opts.getContextNode(); execute_test(testName, params, contextNode); } else { String suiteName = opts.getSuiteName(); List<String> profiles = opts.getProfiles(); if (suiteName != null || profiles.size() == 0) { execute_suite(suiteName, params); } if (profiles.contains("*")) { for (String profile : index.getProfileKeys()) { try { execute_profile(profile, params, false); } catch (Exception e) { jlogger.log(Level.WARNING, e.getMessage(), e.getCause()); } } } else { for (String profile : profiles) { try { execute_profile(profile, params, true); } catch (Exception e) { jlogger.log(Level.WARNING, e.getMessage(), e.getCause()); } } } } } else { throw new Exception("Unsupported mode"); } } finally { if (!web) { SwingForm.destroy(); } if (opts.getLogDir() != null) { // Create xml execution report file LogUtils.createFullReportLog(opts.getLogDir().getAbsolutePath() + File.separator + opts.getSessionId()); } } } public void reexecute_test(String testPath) throws Exception { Document log = LogUtils.readLog(opts.getLogDir(), testPath); String testId = LogUtils.getTestIdFromLog(log); TestEntry test = index.getTest(testId); net.sf.saxon.s9api.DocumentBuilder builder = engine.getBuilder(); XdmNode paramsNode = LogUtils.getParamsFromLog(builder, log); XdmNode contextNode = LogUtils.getContextFromLog(builder, log); XPathContext context = getXPathContext(test, opts.getSourcesName(), contextNode); setTestPath(testPath); executeTest(test, paramsNode, context); if (testPath.equals(opts.getSessionId())) { // Profile not executed in retest mode suiteLog = LogUtils.readLog(opts.getLogDir(), testPath); ArrayList<String> params = opts.getParams(); List<String> profiles = opts.getProfiles(); if (profiles.contains("*")) { for (String profile : index.getProfileKeys()) { try { execute_profile(profile, params, false); } catch (Exception e) { jlogger.log(Level.WARNING, e.getMessage(), e.getCause()); } } } else { for (String profile : profiles) { try { // 2011-12-21 PwD execute_profile(profile, params, true); } catch (Exception e) { jlogger.log(Level.WARNING, e.getMessage(), e.getCause()); } } } } } public int execute_test(String testName, List<String> params, XdmNode contextNode) throws Exception { if (LOGR.isLoggable(Level.FINE)) { String logMsg = String.format( "Preparing test %s for execution, using params:%n %s", testName, params); LOGR.fine(logMsg); } TestEntry test = index.getTest(testName); if (test == null) { throw new Exception("Error: Test " + testName + " not found."); } XdmNode paramsNode = engine.getBuilder().build( new StreamSource(new StringReader(getParamsXML(params)))); if (contextNode == null && test.usesContext()) { String contextNodeXML = "<context><value>" + test.getContext() + "</value></context>"; contextNode = engine.getBuilder().build( new StreamSource(new StringReader(contextNodeXML))); } XPathContext context = getXPathContext(test, opts.getSourcesName(), contextNode); return executeTest(test, paramsNode, context); } public void execute_suite(String suiteName, List<String> params) throws Exception { SuiteEntry suite = null; if (suiteName == null) { Iterator<String> it = index.getSuiteKeys().iterator(); if (!it.hasNext()) { throw new Exception("Error: No suites in sources."); } suite = index.getSuite(it.next()); if (it.hasNext()) { throw new Exception( "Error: Suite name must be specified since there is more than one suite in sources."); } } else { suite = index.getSuite(suiteName); if (suite == null) { throw new Exception("Error: Suite " + suiteName + " not found."); } } defaultResultName = suite.getDefaultResult(); defaultResult = defaultResultName.equals("BestPractice") ? BEST_PRACTICE : PASS; testStack.peek().setDefaultResult(defaultResult); testStack.peek().setResult(defaultResult); ArrayList<String> kvps = new ArrayList<String>(); kvps.addAll(params); Document form = suite.getForm(); if (form != null) { Document results = (Document) form(form, suite.getId()); for (Element value : DomUtils .getElementsByTagName(results, "value")) { kvps.add(value.getAttribute("key") + "=" + value.getTextContent()); } } String name = suite.getPrefix() + ":" + suite.getLocalName(); out.println("Testing suite " + name + " in " + getMode() + " with defaultResult of " + defaultResultName + " ..."); RecordTestResult recordTestResult = new RecordTestResult(); if(opts.getLogDir()!=null){ recordTestResult.recordingStartCheck(suite); recordTestResult.recordingStartClause(suite); } setIndentLevel(1); int result = execute_test(suite.getStartingTest().toString(), kvps, null); recordTestResult.detailTestPath(); reTestCount = 0; out.print("Suite " + suite.getPrefix() + ":" + suite.getLocalName() + " "); if (result == TECore.FAIL || result == TECore.INHERITED_FAILURE) { out.println(MSG_FAIL); } else if (result == TECore.BEST_PRACTICE) { out.println(MSG_BEST_PRACTICE); } else { out.println(MSG_PASS); } if(opts.getLogDir()!=null){ recordTestResult.saveRecordingClause(suite, dirPath); recordTestResult.saveRecordingData(suite, dirPath); } } public void execute_profile(String profileName, List<String> params, boolean required) throws Exception { ProfileEntry profile = index.getProfile(profileName); if (profile == null) { throw new Exception("Error: Profile " + profileName + " not found."); } SuiteEntry suite = index.getSuite(profile.getBaseSuite()); if (suite == null) { throw new Exception("Error: The base suite (" + profile.getBaseSuite().toString() + ") for the profile (" + profileName + ") not found."); } String sessionId = opts.getSessionId(); Document log = LogUtils.readLog(opts.getLogDir(), sessionId); if (log == null) { execute_suite(suite.getId(), params); log = LogUtils.readLog(opts.getLogDir(), sessionId); } suiteLog = log; String testId = LogUtils.getTestIdFromLog(log); List<String> baseParams = LogUtils.getParamListFromLog( engine.getBuilder(), log); TestEntry test = index.getTest(testId); if (suite.getStartingTest().equals(test.getQName())) { ArrayList<String> kvps = new ArrayList<String>(); kvps.addAll(baseParams); kvps.addAll(params); Document form = profile.getForm(); if (form != null) { Document results = (Document) form(form, profile.getId()); for (Element value : DomUtils.getElementsByTagName(results, "value")) { kvps.add(value.getAttribute("key") + "=" + value.getTextContent()); } } setTestPath(sessionId + "/" + profile.getLocalName()); String name = profile.getPrefix() + ":" + profile.getLocalName(); out.println("\nTesting profile " + name + "..."); Document baseLog = LogUtils.makeTestList(opts.getLogDir(), sessionId, profile.getExcludes()); Element baseTest = DomUtils.getElement(baseLog); // out.println(DomUtils.serializeNode(baseLog)); out.print(TECore.INDENT + "Base tests from suite " + suite.getPrefix() + ":" + suite.getLocalName() + " "); String summary = "Not complete"; if ("yes".equals(baseTest.getAttribute("complete"))) { int baseResult = Integer.parseInt(baseTest .getAttribute("result")); if (baseResult == TECore.FAIL || baseResult == TECore.INHERITED_FAILURE) { summary = MSG_FAIL; } else if (verdict == TECore.BEST_PRACTICE) { summary = MSG_BEST_PRACTICE; } else if (verdict == TECore.SKIPPED) { summary = MSG_SKIPPED; } else { summary = MSG_PASS; } } out.println(summary); setIndentLevel(1); String defaultResultName = profile.getDefaultResult(); defaultResult = defaultResultName.equals("BestPractice") ? BEST_PRACTICE : PASS; out.println("\nExecuting profile " + name + " with defaultResult of " + defaultResultName + "..."); int result = execute_test(profile.getStartingTest().toString(), kvps, null); out.print("Profile " + profile.getPrefix() + ":" + profile.getLocalName() + " "); if (result == TECore.FAIL || result == TECore.INHERITED_FAILURE) { summary = MSG_FAIL; } else if (result == TECore.BEST_PRACTICE) { summary = MSG_BEST_PRACTICE; } else if (verdict == TECore.SKIPPED) { summary = MSG_SKIPPED; } else { summary = MSG_PASS; } out.println(summary); } else { if (required) { throw new Exception("Error: Profile " + profileName + " is not a valid profile for session " + sessionId + "."); } } } public XdmNode executeTemplate(TemplateEntry template, XdmNode params, XPathContext context) throws Exception { if (stop) { throw new Exception("Execution was stopped by the user."); } XsltExecutable executable = engine.loadExecutable(template, opts.getSourcesName()); XsltTransformer xt = executable.load(); XdmDestination dest = new XdmDestination(); xt.setDestination(dest); if (template.usesContext() && context != null) { xt.setSource((NodeInfo) context.getContextItem()); } else { xt.setSource(new StreamSource(new StringReader("<nil/>"))); } xt.setParameter(TECORE_QNAME, new ObjValue(this)); if (params != null) { xt.setParameter(TEPARAMS_QNAME, params); } // test may set global verdict, e.g. by calling ctl:fail if (LOGR.isLoggable(Level.FINE)) { LOGR.log(Level.FINE, "Executing TemplateEntry {0}" + template.getQName()); } xt.transform(); XdmNode ret = dest.getXdmNode(); if (ret != null && LOGR.isLoggable(Level.FINE)) { LOGR.log(Level.FINE, "Output:\n" + ret.toString()); } return ret; } static String getLabel(XdmNode n) { String label = n.getAttributeValue(LABEL_QNAME); if (label == null) { XdmNode value = (XdmNode) n.axisIterator(Axis.CHILD).next(); XdmItem childItem = null; try { childItem = value.axisIterator(Axis.CHILD).next(); } catch (Exception e) { // Not an error } if (childItem == null) { XdmSequenceIterator it = value.axisIterator(Axis.ATTRIBUTE); if (it.hasNext()) { label = it.next().getStringValue(); } else { label = ""; } } else if (childItem.isAtomicValue()) { label = childItem.getStringValue(); } else if (childItem instanceof XdmNode) { XdmNode n2 = (XdmNode) childItem; if (n2.getNodeKind() == XdmNodeKind.ELEMENT) { label = "<" + n2.getNodeName().toString() + ">"; } else { label = n2.toString(); } } } return label; } String getAssertionValue(String text, XdmNode paramsVar) { if (text.indexOf("$") < 0) { return text; } String newText = text; XdmNode params = (XdmNode) paramsVar.axisIterator(Axis.CHILD).next(); XdmSequenceIterator it = params.axisIterator(Axis.CHILD); while (it.hasNext()) { XdmNode n = (XdmNode) it.next(); QName qname = n.getNodeName(); if (qname != null) { String tagname = qname.getLocalName(); if (tagname.equals("param")) { String name = n.getAttributeValue(LOCALNAME_QNAME); String label = getLabel(n); newText = StringUtils.replaceAll(newText, "{$" + name + "}", label); } } } newText = StringUtils.replaceAll(newText, "{$context}", contextLabel); return newText; } static String getResultDescription(int result) { if (result == CONTINUE) { return MSG_CONTINUE; } else if (result == BEST_PRACTICE) { return MSG_BEST_PRACTICE; } else if (result == PASS) { return MSG_PASS; } else if (result == NOT_TESTED) { return MSG_NOT_TESTED; } else if (result == SKIPPED) { return MSG_SKIPPED; } else if (result == WARNING) { return MSG_WARNING; } else if (result == INHERITED_FAILURE) { return MSG_INHERITED_FAILURE; } else { return MSG_FAIL; } } /** * Executes a test implemented as an XSLT template. * * @param test * Provides information about the test (gleaned from an entry in * the test suite index). * @param params * A node representing test run arguments. * @param context * A context in which the template is evaluated. * @return An integer value indicating the test result. * @throws Exception * If any error arises while executing the test. */ public int executeTest(TestEntry test, XdmNode params, XPathContext context) throws Exception { testStack.push(test); testType = test.getType(); defaultResult = test.getDefaultResult(); defaultResultName = (defaultResult == BEST_PRACTICE) ? "BestPractice" : "Pass"; Document oldPrevLog = prevLog; if (opts.getMode() == Test.RESUME_MODE) { prevLog = readLog(); } else if (opts.getMode() == Test.REDO_FROM_CACHE_MODE) { prevLog = readLog(); } else { prevLog = null; } String assertion = getAssertionValue(test.getAssertion(), params); //seperate two sub test. out.println("******************************************************************************************************************************"); out.print(indent + "Testing "); out.print(test.getName() + " type " + test.getType()); //Check test is contain client test main layer or not if(rootTestName!=null&&rootTestName.size()>0){ for (int i = 0; i < rootTestName.size(); i++) { if((test.getName()).contains(rootTestName.get(i))){ methodCount=methodCount+1; } } } out.print(" in " + getMode() + " with defaultResult " + defaultResultName + " "); String testName = test.getName() + " type " + test.getType(); System.setProperty("TestName", testName); out.println("(" + testPath + ")..."); if(opts.getLogDir()!=null){ String logDir = opts.getLogDir() + "/" + testPath.split("/")[0]; //create log directory if ("True".equals(System.getProperty("Record"))) { dirPath = new File(logDir + "/test_data"); if (!dirPath.exists()) { if (!dirPath.mkdir()) { System.out.println("Failed to create Error Log!"); } } } } // Delete files for coverage report. if (reTestCount == 0) { if (getMode().contains("Retest")) { if(null!=dirPath){ if (dirPath.isDirectory()) { File[] files = dirPath.listFiles(); if (files != null && files.length > 0) { for (File aFile : files) { aFile.delete(); } } dirPath.delete(); } else { dirPath.delete(); } } reTestCount = 1; } } String oldIndent = indent; indent += INDENT; if (test.usesContext()) { out.println(indent + "Context: " + test.getContext()); } out.println(indent + "Assertion: " + assertion); assertionMsz = assertion; PrintWriter oldLogger = logger; if (opts.getLogDir() != null) { logger = createLog(); logger.println("<log>"); logger.print("<starttest "); logger.print("local-name=\"" + test.getLocalName() + "\" "); logger.print("prefix=\"" + test.getPrefix() + "\" "); logger.print("namespace-uri=\"" + test.getNamespaceURI() + "\" "); logger.print("type=\"" + test.getType() + "\" "); logger.print("defaultResult=\"" + Integer.toString(test.getDefaultResult()) + "\" "); logger.print("path=\"" + testPath + "\" "); logger.println("file=\"" + test.getTemplateFile().getAbsolutePath() + "\">"); logger.println("<assertion>" + StringUtils.escapeXML(assertion) + "</assertion>"); if (params != null) { logger.println(params.toString()); pathURL = params.toString(); } if (test.usesContext()) { logger.print("<context label=\"" + StringUtils.escapeXML(contextLabel) + "\">"); logger.print("<value>"); logger.print(test.getContext()); logger.print("</value>"); logger.println("</context>"); } logger.println("</starttest>"); logger.flush(); } int oldVerdict = this.verdict; test.setResult(PASS); RecordTestResult recordTestResult = new RecordTestResult(); recordTestResult.storeStartTestDetail(test, dirPath); this.verdict = defaultResult; try { executeTemplate(test, params, context); } catch (SaxonApiException e) { jlogger.log(Level.SEVERE, e.getMessage()); DateFormat dateFormat = new SimpleDateFormat(Constants.YYYY_M_MDD_H_HMMSS); Date date = new Date(); try { String path = System.getProperty("PATH") + "/error_log"; File file = new File(path); if (!file.exists()) { if (!file.mkdir()) { System.out.println("Failed to create Error Log!"); } } file = new File(path, "log.txt"); if (!file.exists()) { try { boolean fileCreated = file.createNewFile(); } catch (IOException ioe) { System.out.println("Error while creating empty file: " + ioe); } } OutputStreamWriter writer = new OutputStreamWriter( new FileOutputStream(file, true), "UTF-8"); BufferedWriter fbw = new BufferedWriter(writer); fbw.write(dateFormat.format(date) + " ERROR"); fbw.newLine(); fbw.write("Test Name : " + System.getProperty("TestName")); fbw.newLine(); e.printStackTrace(new PrintWriter(fbw)); fbw.newLine(); fbw.close(); } catch (IOException exep) { System.out.println("Error: " + e.getMessage()); } if (logger != null) { logger.println("<exception><![CDATA[" + e.getMessage() + "]]></exception>"); } this.verdict = FAIL; if (!testStack.isEmpty()) { testStack.pop(); } } finally{ // Check if verdict was already set by a failing subtest if (test.getResult() != INHERITED_FAILURE) { test.setResult(verdict); } if (logger != null) { logger.println("<endtest result=\"" + test.getResult() + "\"/>"); if(test.getIsConformanceClass().equals("true")){ logger.println("<conformanceClass name=\"" + test.getLocalName() + "\"" + " isBasic=\"" + test.getIsBasic() + "\"" + " result=\"" + test.getResult() + "\" />"); } logger.println("</log>"); logger.flush(); logger.close(); } // Add missing info in the log.xml E.g. endtag '</log> or' endtest '<endtest result="1" />'. if(opts.getLogDir() != null && testPath != null){ String logDir = opts.getLogDir() + "/" + testPath; addMissingInfo(logDir, test.getResult()); } } //Create node which contain all test detail. if ("True".equals(System.getProperty("Record"))) { mainRootElement.appendChild(recordTestResult.getMethod()); } assertionMsz = ""; pathURL = ""; messageTest = ""; logger = oldLogger; prevLog = oldPrevLog; indent = oldIndent; DateFormat dateFormat = new SimpleDateFormat(Constants.YYYY_M_MDD_H_HMMSS); Calendar cal = Calendar.getInstance(); out.println(indent + "Test " + test.getName() + " " + getResultDescription(test.getResult())); recordTestResult.storeFinalTestDetail(test, verdict, dateFormat, cal, dirPath); if (LOGR.isLoggable(Level.FINE)) { String msg = String .format("Executed test %s - Verdict: %s", test.getLocalName(), getResultDescription(test.getResult())); LOGR.log(Level.FINE, msg); } //restore previous verdict if the result isn't worse if (this.verdict <= oldVerdict) { this.verdict = oldVerdict; } return test.getResult(); } public void addMissingInfo(String dir, int testResult) { String logdir = dir + File.separator + "log.xml"; DocumentBuilderFactory dbf = null; DocumentBuilder docBuilder = null; Document doc = null; File logfile = new File(logdir); try { dbf = DocumentBuilderFactory.newInstance(); docBuilder = dbf.newDocumentBuilder(); docBuilder.setErrorHandler(null); doc = docBuilder.parse(logfile); } catch (Exception e) { try { FileWriter fw = new FileWriter(logdir, true); BufferedWriter bw = new BufferedWriter(fw); PrintWriter out = new PrintWriter(bw); out.println("</log>"); out.close(); bw.close(); doc = docBuilder.parse(logfile); } catch (Exception ex) { throw new RuntimeException( "Unable to update missing information in " + logdir); } } NodeList nl = doc.getElementsByTagName("endtest"); if (nl.getLength() == 0) { Element root = doc.getDocumentElement(); Element endtest = doc.createElement("endtest"); Attr resultAttribute = doc.createAttribute("result"); resultAttribute.setValue(Integer.toString(testResult)); endtest.setAttributeNode(resultAttribute); root.appendChild(endtest); try { DOMSource source = new DOMSource(doc); TransformerFactory transformerFactory = TransformerFactory .newInstance(); Transformer transformer = transformerFactory.newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); StreamResult result = new StreamResult(logfile); transformer.transform(source, result); } catch (Exception ex) { throw new RuntimeException( "Unable to update missing information in " + logdir); } } } /** * Runs a subtest as directed by a <ctl:call-test> instruction. * * @param context * The context in which the subtest is executed. * @param localName * The [local name] of the subtest. * @param namespaceURI * The [namespace name] of the subtest. * @param params * A NodeInfo object containing test parameters. * @param callId * A node identifier used to build a file path reference for the * test results. * @throws Exception * If an error occcurs while executing the test. */ public synchronized void callTest(XPathContext context, String localName, String namespaceURI, NodeInfo params, String callId) throws Exception { String key = "{" + namespaceURI + "}" + localName; TestEntry test = index.getTest(key); if (logger != null) { logger.println("<testcall path=\"" + testPath + "/" + callId + "\"/>"); logger.flush(); } if (opts.getMode() == Test.RESUME_MODE) { Document doc = LogUtils.readLog(opts.getLogDir(), testPath + "/" + callId); int result = LogUtils.getResultFromLog(doc); // TODO revise the following if (result >= 0) { out.println(indent + "Test " + test.getName() + " " + getResultDescription(result)); if (result == WARNING) { warning(); } else if (result == CONTINUE) { throw new IllegalStateException( "Error: 'continue' is not allowed when a test is called using 'call-test' instruction"); } else if (result != PASS) { inheritedFailure(); } return; } } String oldTestPath = testPath; testPath += "/" + callId; try{ this.verdict = executeTest(test, S9APIUtils.makeNode(params), context); } catch(Exception e){ } finally { testPath = oldTestPath; } if (this.verdict == CONTINUE) { throw new IllegalStateException( "Error: 'continue' is not allowed when a test is called using 'call-test' instruction"); } updateParentTestResult(test); testStack.pop(); } /** * Modifies the result of the parent test according to the result of the * current test. The parent test will be 'tainted' with an inherited failure * if (a) a subtest failed, or (b) a required subtest was skipped. * * @param currTest * The TestEntry for the current test. */ private void updateParentTestResult(TestEntry currTest) { TestEntry parentTest = getParentTest(); if (null == parentTest) return; if (LOGR.isLoggable(Level.FINE)) { LOGR.log( Level.FINE, "Entered setParentTestResult with TestEntry {0} (result={1})", new Object[] { currTest.getQName(), currTest.getResult() }); LOGR.log( Level.FINE, "Parent TestEntry is {0} (result={1})", new Object[] { parentTest.getQName(), parentTest.getResult() }); } switch (currTest.getResult()) { case FAIL: // fall through case INHERITED_FAILURE: parentTest.setResult(INHERITED_FAILURE); break; case SKIPPED: if (!parentTest.getType().equalsIgnoreCase("Optional")) { parentTest.setResult(INHERITED_FAILURE); } break; default: break; } } public void repeatTest(XPathContext context, String localName, String NamespaceURI, NodeInfo params, String callId, int count, int pause) throws Exception { String key = "{" + NamespaceURI + "}" + localName; TestEntry test = index.getTest(key); if (logger != null) { logger.println("<testcall path=\"" + testPath + "/" + callId + "\"/>"); logger.flush(); } if (opts.getMode() == Test.RESUME_MODE) { Document doc = LogUtils.readLog(opts.getLogDir(), testPath + "/" + callId); int result = LogUtils.getResultFromLog(doc); if (result >= 0) { out.println(indent + "Test " + test.getName() + " " + getResultDescription(result)); if (result == WARNING) { warning(); } else if (result != PASS) { inheritedFailure(); } return; } } int oldResult = verdict; String oldTestPath = testPath; testPath += "/" + callId; for (int i = 0; i < count; i++) { executeTest(test, S9APIUtils.makeNode(params), context); testPath = oldTestPath; if (verdict == FAIL && oldResult != FAIL) { // If the child result was FAIL and parent hasn't directly // failed, // set parent result to INHERITED_FAILURE verdict = INHERITED_FAILURE; return; } else if (verdict == CONTINUE) { // System.out.println("Pausing for..."+pause); if (pause > 0 && i < count - 1) { try { Thread.sleep(pause); } catch (Exception e) { e.printStackTrace(); } } } else if (verdict <= oldResult) { // Restore parent result if the child results aren't worse verdict = oldResult; return; } } verdict = FAIL; if (oldResult != FAIL) { // If the child result was FAIL and parent hasn't directly failed, // set parent result to INHERITED_FAILURE verdict = INHERITED_FAILURE; } } public NodeInfo executeXSLFunction(XPathContext context, FunctionEntry fe, NodeInfo params) throws Exception { String oldFnPath = fnPath; CRC32 crc = new CRC32(); crc.update((fe.getPrefix() + fe.getId()).getBytes()); fnPath += Long.toHexString(crc.getValue()) + "/"; XdmNode n = executeTemplate(fe, S9APIUtils.makeNode(params), context); fnPath = oldFnPath; if (n == null) { return null; } return n.getUnderlyingNode(); } public Object callFunction(XPathContext context, String localName, String namespaceURI, NodeInfo params) throws Exception { // System.out.println("callFunction {" + NamespaceURI + "}" + // localName); String key = "{" + namespaceURI + "}" + localName; List<FunctionEntry> functions = index.getFunctions(key); Node paramsNode = NodeOverNodeInfo.wrap(params); List<Element> paramElements = DomUtils.getElementsByTagName(paramsNode, "param"); for (FunctionEntry fe : functions) { if (!fe.isJava()) { boolean valid = true; for (Element el : paramElements) { String uri = el.getAttribute("namespace-uri"); String name = el.getAttribute("local-name"); String prefix = el.getAttribute("prefix"); javax.xml.namespace.QName qname = new javax.xml.namespace.QName( uri, name, prefix); if (!fe.getParams().contains(qname)) { valid = false; break; } } if (valid) { return executeXSLFunction(context, fe, params); } } } for (FunctionEntry fe : functions) { if (fe.isJava()) { int argCount = paramElements.size(); if (fe.getMinArgs() >= argCount && fe.getMaxArgs() <= argCount) { TEClassLoader cl = engine.getClassLoader(opts .getSourcesName()); Method method = Misc.getMethod(fe.getClassName(), fe.getMethod(), cl, argCount); Class<?>[] types = method.getParameterTypes(); Object[] args = new Object[argCount]; for (int i = 0; i < argCount; i++) { Element el = DomUtils.getElementByTagName( paramElements.get(i), "value"); if (types[i].equals(String.class)) { Map<javax.xml.namespace.QName, String> attrs = DomUtils .getAttributes(el); if (attrs.size() > 0) { args[i] = attrs.values().iterator().next(); } else { args[i] = el.getTextContent(); } } else if (types[i].toString().equals("char")) { args[i] = el.getTextContent().charAt(0); } else if (types[i].toString().equals("boolean")) { args[i] = Boolean.parseBoolean(el.getTextContent()); } else if (types[i].toString().equals("byte")) { args[i] = Byte.parseByte(el.getTextContent()); } else if (types[i].toString().equals("short")) { args[i] = Short.parseShort(el.getTextContent()); } else if (types[i].toString().equals("int")) { args[i] = Integer.parseInt(el.getTextContent()); } else if (types[i].toString().equals("long")) { args[i] = Long.parseLong(el.getTextContent()); } else if (types[i].toString().equals("float")) { args[i] = Float.parseFloat(el.getTextContent()); } else if (types[i].toString().equals("double")) { args[i] = Double.parseDouble(el.getTextContent()); } else if (Document.class.isAssignableFrom(types[i])) { args[i] = DomUtils.createDocument(DomUtils .getChildElement(el)); } else if (NodeList.class.isAssignableFrom(types[i])) { args[i] = el.getChildNodes(); } else if (Node.class.isAssignableFrom(types[i])) { args[i] = el.getFirstChild(); } else { throw new Exception("Error: Function " + key + " uses unsupported Java type " + types[i].toString()); } } try { Object instance = null; if (fe.isInitialized()) { // String instkey = fe.getId() + "," + // Integer.toString(fe.getMinArgs()) + "," + // Integer.toString(fe.getMaxArgs()); instance = getFunctionInstance(fe.hashCode()); if (instance == null) { try { instance = Misc.makeInstance( fe.getClassName(), fe.getClassParams(), cl); putFunctionInstance(fe.hashCode(), instance); } catch (Exception e) { throw new XPathException(e); } } } return method.invoke(instance, args); } catch (java.lang.reflect.InvocationTargetException e) { Throwable cause = e.getCause(); String msg = "Error invoking function " + fe.getId() + "\n" + cause.getClass().getName(); if (cause.getMessage() != null) { msg += ": " + cause.getMessage(); } jlogger.log(Level.SEVERE, "InvocationTargetException", e); throw new Exception(msg, cause); } } } } throw new Exception("No function {" + namespaceURI + "}" + localName + " with a compatible signature."); } public void _continue() { this.verdict = CONTINUE; } public void bestPractice() { if (verdict < BEST_PRACTICE) { verdict = BEST_PRACTICE; } } public void notTested() { if (verdict < NOT_TESTED) { verdict = NOT_TESTED; } } public void skipped() { if (verdict < SKIPPED) { verdict = SKIPPED; } } /** * A test with defaultResult of BEST_PRACTICE. */ public void pass() { if (verdict < PASS) { verdict = PASS; } } public void warning() { if (verdict < WARNING) { verdict = WARNING; } } public void inheritedFailure() { if (verdict < INHERITED_FAILURE) { verdict = INHERITED_FAILURE; } } public void fail() { this.verdict = FAIL; } public String getResult() { return getResultDescription(verdict); } public String getMode() { return Test.getModeName(opts.getMode()); } public void setContextLabel(String label) { contextLabel = label; } public String getFormHtml() { return formHtml; } public void setFormHtml(String html) { this.formHtml = html; } public Document getFormResults() { return formResults; } public void setFormResults(Document doc) { try { StringWriter sw = new StringWriter(); // Fortify Mod: prevent external entity injection TransformerFactory tf = TransformerFactory.newInstance(); tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); Transformer transformer = tf.newTransformer(); // End Fortify Mod transformer.setOutputProperty(OutputKeys.INDENT, "yes"); transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); transformer.transform(new DOMSource(doc), new StreamResult(sw)); LOGR.info("Setting form results:\n " + sw.toString()); } catch(Exception e) { LOGR.log(Level.SEVERE, "Failed to log the form results", e); } this.formResults = doc; } public Map<String, Element> getFormParsers() { return formParsers; } public Document readLog() throws Exception { return LogUtils.readLog(opts.getLogDir(), testPath); } public PrintWriter createLog() throws Exception { return LogUtils.createLog(opts.getLogDir(), testPath); } // Get a File pointer to a file reference (in XML) public static File getFile(NodeList fileNodes) { File file = null; for (int i = 0; i < fileNodes.getLength(); i++) { Element e = (Element) fileNodes.item(i); String type = e.getAttribute("type"); try { // URL, File, or Resource if (type.equals("url")) { URL url = new URL(e.getTextContent()); file = new File(url.toURI()); } else if (type.equals("file")) { file = new File(e.getTextContent()); } else if (type.equals("resource")) { ClassLoader cl = Thread.currentThread() .getContextClassLoader(); file = new File(cl.getResource(e.getTextContent()) .getFile()); } else { System.out .println("Incorrect file reference: Unknown type!"); } } catch (Exception exception) { System.err.println("Error getting file. " + exception.getMessage()); jlogger.log(Level.SEVERE, "Error getting file. " + exception.getMessage(), e); return null; } } return file; } // BEGIN SOAP SUPPORT public NodeList soap_request(Document ctlRequest, String id) throws Throwable { Element request = (Element) ctlRequest.getElementsByTagNameNS( Test.CTL_NS, "soap-request").item(0); if (opts.getMode() == Test.RESUME_MODE && prevLog != null) { for (Element request_e : DomUtils.getElementsByTagName(prevLog, "soap-request")) { if (request_e.getAttribute("id").equals(fnPath + id)) { logger.println(DomUtils.serializeNode(request_e)); logger.flush(); Element response_e = DomUtils.getElementByTagName( request_e, "response"); Element content_e = DomUtils.getElementByTagName( response_e, "content"); return content_e.getChildNodes(); // return DomUtils.getChildElement(content_e); } } } String logTag = "<soap-request id=\"" + fnPath + id + "\">\n"; logTag += DomUtils.serializeNode(request) + "\n"; // if (logger != null) { // logger.println("<request id=\"" + fnPath + id + "\">"); // logger.println(DomUtils.serializeNode(request)); // } Exception ex = null; Element response = null; Element parserInstruction = null; NodeList nl = request.getChildNodes(); long elapsedTime = 0; for (int i = 0; i < nl.getLength(); i++) { Node n = nl.item(i); if (n.getNodeType() == Node.ELEMENT_NODE && !n.getNamespaceURI().equals(CTL_NS)) { parserInstruction = (Element) n; } } try { Date before = new Date(); URLConnection uc = build_soap_request(request); response = parse(uc, parserInstruction); Date after = new Date(); elapsedTime = after.getTime() - before.getTime(); // Adding the exchange time in the response as comment the format is // the following // <!--Response received in [XXX] milliseconds--> // the comment is included in the first tag of the response // SOAP:Envelope in case a SOAP message is returned the specific // interface tag if a SOAP parser is applied Element content = DomUtils.getElementByTagName(response, "content"); if (content != null) { nl = content.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node n = nl.item(i); if (n.getNodeType() == Node.ELEMENT_NODE) { Document doc; doc = response.getOwnerDocument(); Comment comm = doc .createComment("Response received in [" + elapsedTime + "] milliseconds"); n.appendChild(comm); } } } logTag += DomUtils.serializeNode(response) + "\n"; jlogger.log(Level.FINE, DomUtils.serializeNode(response)); } catch (Exception e) { ex = e; } logTag += "<!-- elapsed time :" + elapsedTime + " (milliseconds) -->"; logTag += "</soap-request>"; if (logger != null) { logger.println(logTag); logger.flush(); } if (ex == null) { Element parser = DomUtils.getElementByTagName(response, "parser"); if (parser != null) { String text = parser.getTextContent(); if (text.length() > 0) { out.println(parser.getTextContent()); } } Element content = DomUtils.getElementByTagName(response, "content"); return content.getChildNodes(); } else { throw ex; } } /** * Create SOAP request, sends it and return an URL Connection ready to be * parsed. * * @param xml * the soap-request node (from CTL) * * @return The URL Connection * * @throws Exception * the exception * * <soap-request version="1.1|1.2" charset="UTF-8"> * <url>http://blah</url> <action>Some-URI</action> <headers> * <header MutUnderstand="true" rely="true" role="http://etc"> * <t:Transaction xmlns:t="some-URI" >5</t:Transaction> * </header> </headers> <body> <m:GetLastTradePrice * xmlns:m="Some-URI"> <symbol>DEF</symbol> * </m:GetLastTradePrice> </body> <parsers:SOAPParser * return="content"> <parsers:XMLValidatingParser> * <parsers:schemas> <parsers:schema * type="url">http://blah/schema.xsd</parsers:schema> * </parsers:schemas> </parsers:XMLValidatingParser> * </parsers:SOAPParser> </soap-request> */ static public URLConnection build_soap_request(Node xml) throws Exception { String sUrl = null; String method = "POST"; String charset = ((Element) xml).getAttribute("charset").equals("") ? ((Element) xml) .getAttribute("charset") : "UTF-8"; String version = ((Element) xml).getAttribute("version"); String action = ""; String contentType = ""; Element body = null; // Read in the test information (from CTL) NodeList nl = xml.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node n = nl.item(i); if (n.getNodeType() == Node.ELEMENT_NODE) { if (n.getLocalName().equals("url")) { sUrl = n.getTextContent(); } else if (n.getLocalName().equals("action")) { action = n.getTextContent(); } // else if (n.getLocalName().equals("header")) { // header = (org.w3c.dom.Element) n; /* * } */else if (n.getLocalName().equals("body")) { body = (org.w3c.dom.Element) n; } } } // Get the list of the header blocks needed to build the SOAP Header // section List<Element> headerBloks = DomUtils.getElementsByTagNameNS(xml, CTL_NS, HEADER_BLOCKS); // Open the URLConnection URLConnection uc = new URL(sUrl).openConnection(); if (uc instanceof HttpURLConnection) { ((HttpURLConnection) uc).setRequestMethod(method); } uc.setDoOutput(true); byte[] bytes = null; // SOAP POST bytes = SoapUtils.getSoapMessageAsByte(version, headerBloks, body, charset); // System.out.println("SOAP MESSAGE " + new String(bytes)); uc.setRequestProperty("User-Agent", "Team Engine 1.2"); uc.setRequestProperty("Cache-Control", "no-cache"); uc.setRequestProperty("Pragma", "no-cache"); uc.setRequestProperty("charset", charset); uc.setRequestProperty("Content-Length", Integer.toString(bytes.length)); if (version.equals(SOAP_V_1_1)) { // Handle HTTP binding for SOAP 1.1 // uc.setRequestProperty("Accept", "application/soap+xml"); uc.setRequestProperty("Accept", "text/xml"); uc.setRequestProperty("SOAPAction", action); contentType = "text/xml"; if (!charset.equals("")) { contentType = contentType + "; charset=" + charset; } uc.setRequestProperty("Content-Type", contentType); } else { // Handle HTTP binding for SOAP 1.2 uc.setRequestProperty("Accept", "application/soap+xml"); contentType = "application/soap+xml"; if (!charset.equals("")) { contentType = contentType + "; charset=" + charset; } if (!action.equals("")) { contentType = contentType + "; action=" + action; } uc.setRequestProperty("Content-Type", contentType); } OutputStream os = uc.getOutputStream(); os.write(bytes); return uc; } /** * Implements ctl:request. Create and send an HTTP request then return an * HttpResponse. Invoke any specified parsers on the response to validate * it, change its format or derive specific information from it. */ public NodeList request(Document ctlRequest, String id) throws Throwable { Element request = (Element) ctlRequest.getElementsByTagNameNS( Test.CTL_NS, "request").item(0); if (opts.getMode() == Test.RESUME_MODE && prevLog != null) { for (Element request_e : DomUtils.getElementsByTagName(prevLog, "request")) { if (request_e.getAttribute("id").equals(fnPath + id)) { logger.println(DomUtils.serializeNode(request_e)); logger.flush(); Element response_e = DomUtils.getElementByTagName( request_e, "response"); Element content_e = DomUtils.getElementByTagName( response_e, "content"); return content_e.getChildNodes(); // return DomUtils.getChildElement(content_e); } } } String logTag = "<request id=\"" + fnPath + id + "\">\n"; logTag += DomUtils.serializeNode(request) + "\n"; // if (logger != null) { // logger.println("<request id=\"" + fnPath + id + "\">"); // logger.println(DomUtils.serializeNode(request)); // } long elapsedTime = 0; Exception ex = null; Element response = null; Element parserInstruction = null; NodeList nl = request.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node n = nl.item(i); if (n.getNodeType() == Node.ELEMENT_NODE && !n.getNamespaceURI().equals(CTL_NS)) { parserInstruction = (Element) n; } } try { Date before = new Date(); URLConnection uc = build_request(request); response = parse(uc, parserInstruction); Date after = new Date(); elapsedTime = after.getTime() - before.getTime(); // Adding the exchange time in the response as comment the format is // the following // <!--Response received in [XXX] milliseconds--> // the comment is included in the first tag of the response Element content = DomUtils.getElementByTagName(response, "content"); if (content != null) { nl = content.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node n = nl.item(i); if (n.getNodeType() == Node.ELEMENT_NODE) { Document doc; doc = response.getOwnerDocument(); Comment comm = doc .createComment("Response received in [" + elapsedTime + "] milliseconds"); n.appendChild(comm); } } } logTag += DomUtils.serializeNode(response) + "\n"; // if (logger != null) { // logger.println(DomUtils.serializeNode(response)); // } } catch (Exception e) { ex = e; } // logTag += "<!-- elapsed time :"+elapsedTime+" (milliseconds) -->"; logTag += "</request>"; if (logger != null) { // logger.println("</request>"); logger.println(logTag); logger.flush(); } if (ex == null) { Element parser = DomUtils.getElementByTagName(response, "parser"); if (parser != null) { String text = parser.getTextContent(); if (text.length() > 0) { out.println(parser.getTextContent()); } } Element content = DomUtils.getElementByTagName(response, "content"); return content.getChildNodes(); } else { throw ex; } } /** * Submits a request to some HTTP endpoint using the given request details. * * @param xml * An ctl:request element. * @return A URLConnection object representing an open communications link. * @throws Exception * If any error occurs while submitting the request or * establishing a conection. */ public URLConnection build_request(Node xml) throws Exception { Node body = null; ArrayList<String[]> headers = new ArrayList<String[]>(); ArrayList<Node> parts = new ArrayList<Node>(); String sUrl = null; String sParams = ""; String method = "GET"; String charset = "UTF-8"; boolean multipart = false; // Read in the test information (from CTL) NodeList nl = xml.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node n = nl.item(i); if (n.getNodeType() == Node.ELEMENT_NODE) { if (n.getLocalName().equals("url")) { sUrl = n.getTextContent(); } else if (n.getLocalName().equals("method")) { method = n.getTextContent().toUpperCase(); } else if (n.getLocalName().equals("header")) { headers.add(new String[] { ((Element) n).getAttribute("name"), n.getTextContent() }); } else if (n.getLocalName().equals("param")) { if (sParams.length() > 0) { sParams += "&"; } sParams += ((Element) n).getAttribute("name") + "=" + n.getTextContent(); // WARNING! May break some existing test suites // + URLEncoder.encode(n.getTextContent(), "UTF-8"); } else if (n.getLocalName().equals("dynamicParam")) { String name = null; String val = null; NodeList dpnl = n.getChildNodes(); for (int j = 0; j < dpnl.getLength(); j++) { Node dpn = dpnl.item(j); if (dpn.getNodeType() == Node.ELEMENT_NODE) { if (dpn.getLocalName().equals("name")) { name = dpn.getTextContent(); } else if (dpn.getLocalName().equals("value")) { val = dpn.getTextContent(); // val = // URLEncoder.encode(dpn.getTextContent(),"UTF-8"); } } } if (name != null && val != null) { if (sParams.length() > 0) sParams += "&"; sParams += name + "=" + val; } } else if (n.getLocalName().equals("body")) { body = n; } else if (n.getLocalName().equals("part")) { parts.add(n); } } } // Complete GET KVP syntax if (method.equals("GET") && sParams.length() > 0) { if (sUrl.indexOf("?") == -1) { sUrl += "?"; } else if (!sUrl.endsWith("?") && !sUrl.endsWith("&")) { sUrl += "&"; } sUrl += sParams; } // System.out.println(sUrl); TransformerFactory tf = TransformerFactory.newInstance(); // Fortify Mod: prevent external entity injection tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); Transformer t = tf.newTransformer(); // Open the URLConnection URLConnection uc = new URL(sUrl).openConnection(); if (uc instanceof HttpURLConnection) { ((HttpURLConnection) uc).setRequestMethod(method); } // POST setup (XML payload and header information) if (method.equals("POST") || method.equals("PUT")) { uc.setDoOutput(true); byte[] bytes = null; String mime = null; // KVP over POST if (body == null) { bytes = sParams.getBytes(); mime = "application/x-www-form-urlencoded"; } // XML POST else { String bodyContent = ""; NodeList children = body.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { if (children.item(i).getNodeType() == Node.ELEMENT_NODE) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); t.transform(new DOMSource(children.item(i)), new StreamResult(baos)); bodyContent = baos.toString(); bytes = baos.toByteArray(); if (mime == null) { mime = "application/xml; charset=" + charset; } break; } } if (bytes == null) { bytes = body.getTextContent().getBytes(); mime = "text/plain"; } // Add parts if present if (parts.size() > 0) { String prefix = "--"; String boundary = "7bdc3bba-e2c9-11db-8314-0800200c9a66"; String newline = "\r\n"; multipart = true; // Set main body and related headers ByteArrayOutputStream contentBytes = new ByteArrayOutputStream(); String bodyPart = prefix + boundary + newline; bodyPart += "Content-Type: " + mime + newline + newline; bodyPart += bodyContent; writeBytes(contentBytes, bodyPart.getBytes(charset)); // Append all parts to the original body, seperated by the // boundary sequence for (int i = 0; i < parts.size(); i++) { Element currentPart = (Element) parts.get(i); String cid = currentPart.getAttribute("cid"); if (cid.indexOf("cid:") != -1) { cid = cid.substring(cid.indexOf("cid:") + "cid:".length()); } String contentType = currentPart .getAttribute("content-type"); // Default encodings and content-type if (contentType.equals("application/xml")) { contentType = "application/xml; charset=" + charset; } if (contentType == null || contentType.equals("")) { contentType = "application/octet-stream"; } // Set headers for each part String partHeaders = newline + prefix + boundary + newline; partHeaders += "Content-Type: " + contentType + newline; partHeaders += "Content-ID: <" + cid + ">" + newline + newline; writeBytes(contentBytes, partHeaders.getBytes(charset)); // Get the fileName, if it exists NodeList files = currentPart.getElementsByTagNameNS( CTL_NS, "file"); // Get part for a specified file if (files.getLength() > 0) { File contentFile = getFile(files); InputStream is = new FileInputStream(contentFile); long length = contentFile.length(); byte[] fileBytes = new byte[(int) length]; int offset = 0; int numRead = 0; while (offset < fileBytes.length && (numRead = is.read(fileBytes, offset, fileBytes.length - offset)) >= 0) { offset += numRead; } is.close(); writeBytes(contentBytes, fileBytes); } // Get part from inline data (or xi:include) else { // Text if (currentPart.getFirstChild() instanceof Text) { writeBytes(contentBytes, currentPart .getTextContent().getBytes(charset)); } // XML else { writeBytes( contentBytes, DomUtils.serializeNode( currentPart.getFirstChild()) .getBytes(charset)); } } } String endingBoundary = newline + prefix + boundary + prefix + newline; writeBytes(contentBytes, endingBoundary.getBytes(charset)); bytes = contentBytes.toByteArray(); // Global Content-Type and Length to be added after the // parts have been parsed mime = "multipart/related; type=\"" + mime + "\"; boundary=\"" + boundary + "\""; // String contentsString = new String(bytes, charset); // System.out.println("Content-Type: "+mime+"\n"+contentsString); } } // Set headers if (body != null) { String mid = ((Element) body).getAttribute("mid"); if (mid != null && !mid.equals("")) { if (mid.indexOf("mid:") != -1) { mid = mid.substring(mid.indexOf("mid:") + "mid:".length()); } uc.setRequestProperty("Message-ID", "<" + mid + ">"); } } uc.setRequestProperty("Content-Type", mime); uc.setRequestProperty("Content-Length", Integer.toString(bytes.length)); // Enter the custom headers (overwrites the defaults if present) for (int i = 0; i < headers.size(); i++) { String[] header = headers.get(i); if (multipart && header[0].toLowerCase().equals("content-type")) { } else { uc.setRequestProperty(header[0], header[1]); } } OutputStream os = uc.getOutputStream(); os.write(bytes); } return uc; } public static void writeBytes(ByteArrayOutputStream baos, byte[] bytes) { baos.write(bytes, 0, bytes.length); } public Element parse(Document parse_instruction, String xsl_version) throws Throwable { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); // Fortify Mod: prevent external entity injection dbf.setExpandEntityReferences(false); DocumentBuilder db = dbf.newDocumentBuilder(); TransformerFactory tf = TransformerFactory.newInstance(); // Fortify Mod: prevent external entity injection tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); Transformer t = null; Node content = null; Document parser_instruction = null; Element parse_element = (Element) parse_instruction .getElementsByTagNameNS(CTL_NS, "parse").item(0); NodeList children = parse_element.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { if (children.item(i).getNodeType() == Node.ELEMENT_NODE) { Element e = (Element) children.item(i); if (e.getNamespaceURI().equals(XSL_NS) && e.getLocalName().equals("output")) { Document doc = db.newDocument(); Element transform = doc .createElementNS(XSL_NS, "transform"); transform.setAttribute("version", xsl_version); doc.appendChild(transform); Element output = doc.createElementNS(XSL_NS, "output"); NamedNodeMap atts = e.getAttributes(); for (int j = 0; j < atts.getLength(); j++) { Attr a = (Attr) atts.item(i); output.setAttribute(a.getName(), a.getValue()); } transform.appendChild(output); Element template = doc.createElementNS(XSL_NS, "template"); template.setAttribute("match", "node()|@*"); transform.appendChild(template); Element copy = doc.createElementNS(XSL_NS, "copy"); template.appendChild(copy); Element apply = doc.createElementNS(XSL_NS, "apply-templates"); apply.setAttribute("select", "node()|@*"); copy.appendChild(apply); t = tf.newTransformer(new DOMSource(doc)); } else if (e.getLocalName().equals("content")) { NodeList children2 = e.getChildNodes(); for (int j = 0; j < children2.getLength(); j++) { if (children2.item(j).getNodeType() == Node.ELEMENT_NODE) { content = children2.item(j); } } if (content == null) { content = children2.item(0); } } else { parser_instruction = db.newDocument(); tf.newTransformer().transform(new DOMSource(e), new DOMResult(parser_instruction)); } } } if (t == null) { t = tf.newTransformer(); } File temp = File.createTempFile("$te_", ".xml"); if (content.getNodeType() == Node.TEXT_NODE) { RandomAccessFile raf = new RandomAccessFile(temp, "rw"); raf.writeBytes(((Text) content).getTextContent()); raf.close(); } else { t.transform(new DOMSource(content), new StreamResult(temp)); } URLConnection uc = temp.toURI().toURL().openConnection(); Element result = parse(uc, parser_instruction); temp.delete(); return result; } /** * Parses the content retrieved from some URI and builds a DOM Document * containing information extracted from the response message. Subsidiary * parsers are invoked in accord with the supplied parser instructions. * * @param uc * A URLConnection object. * @param instruction * A Document or Element node containing parser instructions. * @return An Element containing selected info from a URLConnection as * specified by instruction Element and children. */ public Element parse(URLConnection uc, Node instruction) throws Throwable { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); // Fortify Mod: Disable entity expansion to foil External Entity Injections dbf.setExpandEntityReferences(false); DocumentBuilder db = dbf.newDocumentBuilder(); Document response_doc = db.newDocument(); return parse(uc, instruction, response_doc); } /** * Invoke a parser or chain of parsers as specified by instruction element * and children. Parsers in chain share uc, strip off their own * instructions, and pass child instructions to next parser in chain. Final * parser in chain modifies content. All parsers in chain can return info in * attributes and child elements of instructions. If parser specified in * instruction, call it to return specified info from uc. */ public Element parse(URLConnection uc, Node instruction, Document response_doc) throws Exception { // Fortify Mod: To prevent external entity injections TransformerFactory tf = TransformerFactory.newInstance(); tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); Transformer idt = tf.newTransformer(); // End Fortify Mod Element parser_e = response_doc.createElement("parser"); Element response_e = response_doc.createElement("response"); Element content_e = response_doc.createElement("content"); if (instruction == null) { InputStream is = null; uc.connect(); String contentType = uc.getContentType(); try { is = URLConnectionUtils.getInputStream(uc); if (contentType != null && contentType.contains("xml")) { // a crude check idt.transform(new StreamSource(is), new DOMResult(content_e)); } else { content_e.setTextContent(IOUtils.inputStreamToString(is)); } } finally { if (null != is) is.close(); } } else { Element instruction_e; if (instruction instanceof Element) { instruction_e = (Element) instruction; } else { instruction_e = ((Document) instruction).getDocumentElement(); } String key = "{" + instruction_e.getNamespaceURI() + "}" + instruction_e.getLocalName(); ParserEntry pe = index.getParser(key); Object instance = null; if (pe.isInitialized()) { instance = parserInstances.get(key); if (instance == null) { try { TEClassLoader cl = engine.getClassLoader(opts .getSourcesName()); instance = Misc.makeInstance(pe.getClassName(), pe.getClassParams(), cl); } catch (Exception e) { throw new Exception("Can't instantiate parser " + pe.getName(), e); } parserInstances.put(key, instance); } } Method method = parserMethods.get(key); if (method == null) { TEClassLoader cl = engine.getClassLoader(opts.getSourcesName()); method = Misc.getMethod(pe.getClassName(), pe.getMethod(), cl, 3, 4); parserMethods.put(key, method); } StringWriter swLogger = new StringWriter(); PrintWriter pwLogger = new PrintWriter(swLogger); int arg_count = method.getParameterTypes().length; Object[] args = new Object[arg_count]; args[0] = uc; args[1] = instruction_e; args[2] = pwLogger; if (arg_count > 3) { args[3] = this; } Object return_object; try { if (LOGR.isLoggable(Level.FINER)) { LOGR.finer("Invoking method " + method.toGenericString() + "size args[] = " + args.length + "\n args[0]: " + args[0].toString() + "\n args[1]:\n" + DomUtils.serializeNode((Node) args[1])); } return_object = method.invoke(instance, args); } catch (java.lang.reflect.InvocationTargetException e) { Throwable cause = e.getCause(); String msg = "Error invoking parser " + pe.getId() + "\n" + cause.getClass().getName(); if (cause.getMessage() != null) { msg += ": " + cause.getMessage(); } jlogger.log(Level.SEVERE, msg, e); throw e; } pwLogger.close(); if (return_object instanceof Node) { idt.transform(new DOMSource((Node) return_object), new DOMResult(content_e)); } else if (return_object != null) { content_e.appendChild(response_doc.createTextNode(return_object .toString())); } parser_e.setAttribute("prefix", instruction_e.getPrefix()); parser_e.setAttribute("local-name", instruction_e.getLocalName()); parser_e.setAttribute("namespace-uri", instruction_e.getNamespaceURI()); parser_e.setTextContent(swLogger.toString()); } response_e.appendChild(parser_e); response_e.appendChild(content_e); return response_e; } public Node message(String message, String id) { String formatted_message = indent + message.trim().replaceAll("\n", "\n" + indent); String messageTrim = message.trim().replaceAll("\n", "\n" + indent); if (!(messageTrim.contains("Clause") || messageTrim.contains("Purpose") || messageTrim.contains("TestName"))) { out.println(formatted_message); messageTest = message; } else { if (messageTrim.contains("TestName")) { TESTNAME = messageTrim.replace("TestName : ", ""); if(rootTestName!=null&&rootTestName.size()>0){ for (int i = 0; i < rootTestName.size(); i++) { if(messageTrim.contains(rootTestName.get(i))){ rootNo=i+1; } } } } else if (messageTrim.contains("Clause")) { Clause = messageTrim.replace("Clause : ", "");; } else { Purpose = messageTrim.replace("Purpose : ", "");; } if ((rootNo != 0) && (!"".equals(Clause)) && (!"".equals(Purpose))) { RecordTestResult recordTestResult = new RecordTestResult(); mainRootElementClause.appendChild(recordTestResult.getClause()); Clause = ""; Purpose = ""; rootNo = 0; } } if (logger != null) { logger.println("<message id=\"" + id + "\"><![CDATA[" + message + "]]></message>"); } return null; } public void putLogCache(String id, Document xmlToCache) { if (logger != null) { String xmlString = DomUtils.serializeNode(xmlToCache); logger.println("<cache id=\"" + id + "\">" + xmlString + "</cache>"); } } public Element getLogCache(String id) { Element child_e = null; if (prevLog != null) { for (Element cache_e : DomUtils.getElementsByTagName(prevLog, "cache")) { if (cache_e.getAttribute("id").equals(id)) { child_e = DomUtils.getChildElement(cache_e); } } } if (suiteLog != null && child_e == null) { for (Element cache_e : DomUtils.getElementsByTagName(suiteLog, "cache")) { if (cache_e.getAttribute("id").equals(id)) { child_e = DomUtils.getChildElement(cache_e); } } } return (child_e == null) ? null : child_e; } /** * Converts CTL input form elements to generate a Swing-based or XHTML form * and reports the results of processing the submitted form. The results * document is produced in (web context) or * {@link SwingForm.CustomFormView#submitData}. * * @param ctlForm * a DOM Document representing a <ctl:form> element. * @throws java.lang.Exception * @return a DOM Document containing the resulting <values> element as * the document element. */ public Node form(Document ctlForm, String id) throws Exception { if (opts.getMode() == Test.RESUME_MODE && prevLog != null) { for (Element e : DomUtils.getElementsByTagName(prevLog, "formresults")) { if (e.getAttribute("id").equals(fnPath + id)) { logger.println(DomUtils.serializeNode(e)); logger.flush(); return DomUtils.getChildElement(e); } } } String name = Thread.currentThread().getName(); Element form = (Element) ctlForm.getElementsByTagNameNS(CTL_NS, "form") .item(0); NamedNodeMap attrs = form.getAttributes(); Attr attr = (Attr) attrs.getNamedItem("name"); if (attr != null) { name = attr.getValue(); } for (Element parseInstruction : DomUtils.getElementsByTagNameNS(form, CTL_NS, "parse")) { String key = parseInstruction.getAttribute("file"); formParsers.put(key, DomUtils.getChildElement(parseInstruction)); } // Determine if there are file widgets or not boolean hasFiles = false; List<Element> inputs = DomUtils.getElementsByTagName(form, "input"); inputs.addAll(DomUtils.getElementsByTagNameNS(form, "http://www.w3.org/1999/xhtml", "input")); for (Element input : inputs) { if (input.getAttribute("type").toLowerCase().equals("file")) { hasFiles = true; break; } } // Get "method" attribute - "post" or "get" attr = (Attr) attrs.getNamedItem("method"); String method = "get"; if (attr != null) { method = attr.getValue().toLowerCase(); } else if (hasFiles) { method = "post"; } XsltTransformer formTransformer = engine.getFormExecutable().load(); formTransformer.setSource(new DOMSource(ctlForm)); formTransformer.setParameter(new QName("title"), new XdmAtomicValue( name)); formTransformer.setParameter(new QName("web"), new XdmAtomicValue( web ? "yes" : "no")); formTransformer.setParameter(new QName("files"), new XdmAtomicValue( hasFiles ? "yes" : "no")); formTransformer.setParameter(new QName("thread"), new XdmAtomicValue( Long.toString(Thread.currentThread().getId()))); formTransformer.setParameter(new QName("method"), new XdmAtomicValue( method)); formTransformer.setParameter(new QName("base"), new XdmAtomicValue(opts.getBaseURI())); formTransformer.setParameter(new QName("action"), new XdmAtomicValue( getTestServletURL())); StringWriter sw = new StringWriter(); Serializer serializer = new Serializer(); serializer.setOutputWriter(sw); serializer.setOutputProperty(Serializer.Property.OMIT_XML_DECLARATION, "yes"); formTransformer.setDestination(serializer); formTransformer.transform(); this.formHtml = sw.toString(); if (LOGR.isLoggable(Level.FINE)) LOGR.fine(this.formHtml); if (!recordedForms.isEmpty()) { RecordedForm.create(recordedForms.next(), this); } else if (!web) { int width = 700; int height = 500; attr = (Attr) attrs.getNamedItem("width"); if (attr != null) { width = Integer.parseInt(attr.getValue()); } attr = (Attr) attrs.getNamedItem("height"); if (attr != null) { height = Integer.parseInt(attr.getValue()); } SwingForm.create(name, width, height, this); } while (formResults == null) { if (stop) { formParsers.clear(); throw new Exception("Execution was stopped by the user."); } Thread.sleep(250); } Document doc = formResults; if (LOGR.isLoggable(Level.FINE)) LOGR.fine(DomUtils.serializeNode(doc)); formResults = null; formParsers.clear(); if (logger != null) { logger.println("<formresults id=\"" + fnPath + id + "\">"); logger.println(DomUtils.serializeNode(doc)); logger.println("</formresults>"); } return doc; } public void setIndentLevel(int level) { indent = ""; for (int i = 0; i < level; i++) { indent += INDENT; } } public String getOutput() { String output = threadOutput.toString(); threadOutput.reset(); return output; } public void stopThread() throws Exception { stop = true; while (!threadComplete) { Thread.sleep(100); } } public boolean isThreadComplete() { return threadComplete; } public void run() { threadComplete = false; // activeThread = Thread.currentThread(); try { opts.testLogDir.mkdir(); threadOutput = new ByteArrayOutputStream(); out = new PrintStream(threadOutput); execute(); out.close(); } catch (Exception e) { jlogger.log(Level.SEVERE, "", e); } // activeThread = null; threadComplete = true; } public File getLogDir() { return opts.getLogDir(); } public PrintStream getOut() { return out; } public void setOut(PrintStream out) { this.out = out; } public String getTestPath() { return testPath; } /** * Returns the location of the directory containing the test run output. * * @return A String representing a file URI denoting the path name of a * directory. */ public String getTestRunDirectory() { String logDirURI = opts.getLogDir().toURI().toString(); return logDirURI + opts.getSessionId(); } public void setTestPath(String testPath) { this.testPath = testPath; } public boolean isWeb() { return web; } public void setWeb(boolean web) { this.web = web; } public Object getFunctionInstance(Integer key) { return functionInstances.get(key); } public Object putFunctionInstance(Integer key, Object instance) { return functionInstances.put(key, instance); } public Engine getEngine() { return engine; } public Index getIndex() { return index; } public RuntimeOptions getOpts() { return opts; } public String getTestServletURL() { return testServletURL; } public void setTestServletURL(String testServletURL) { this.testServletURL = testServletURL; } /** * Builds a DOM Document representing a classpath resource. * * @param name * The name of an XML resource. * @return A Document node, or {@code null} if the resource cannot be parsed * for any reason. */ public Document findXMLResource(String name) { URL url = this.getClass().getResource(name); DocumentBuilderFactory docFactory = DocumentBuilderFactory .newInstance(); docFactory.setNamespaceAware(true); // Fortify Mod: Disable entity expansion to foil External Entity Injections docFactory.setExpandEntityReferences(false); Document doc = null; try { DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); doc = docBuilder.parse(url.toURI().toString()); } catch (Exception e) { LOGR.log(Level.WARNING, "Failed to parse classpath resource " + name, e); } return doc; } }