/******************************************************************************* * Copyright (c) 2013 Rene Schneider, GEBIT Solutions GmbH and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html *******************************************************************************/ package de.gebit.integrity.tests.junit; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.jdom.Attribute; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.jdom.input.SAXBuilder; import org.jdom.output.Format; import org.jdom.output.XMLOutputter; import de.gebit.integrity.runner.TestModel; import de.gebit.integrity.runner.TestRunner; import de.gebit.integrity.runner.callbacks.CompoundTestRunnerCallback; import de.gebit.integrity.runner.callbacks.TestRunnerCallback; import de.gebit.integrity.runner.callbacks.console.ConsoleTestCallback; import de.gebit.integrity.runner.callbacks.xml.TransformHandling; import de.gebit.integrity.runner.callbacks.xml.XmlWriterTestCallback; import de.gebit.integrity.runner.exceptions.ModelLoadException; import de.gebit.integrity.runner.providers.FilesystemTestResourceProvider; /** * Abstract base class for Integrity JUnit tests. * * * @author Rene Schneider - initial API and implementation * */ public abstract class IntegrityJUnitTest { /** * Directory where reference result files are located. */ private static final String REFERENCE_RESULT_DIRECTORY = "results/"; /** * Pattern to replace object IDs. */ private static final Pattern OBJECT_ID_PATTERN = Pattern.compile("^(.*@)[0-9,a-f]+$"); /** * Runs a specified Integrity suite in a freshly started test runner. The result XML document is returned. * * @param aSuiteName * the name of the root suite * @return the result document * @throws ModelLoadException * @throws IOException * @throws JDOMException */ protected Document executeIntegritySuite(String[] someFileNames, String aSuiteName, String aVariantName) throws ModelLoadException, IOException, JDOMException { File tempXmlFile = null; List<File> tempFileList = new ArrayList<File>(); tempFileList.add(new File("integrity/fixtures")); for (String tempFileName : someFileNames) { tempFileList.add(new File(tempFileName)); } FilesystemTestResourceProvider tempResourceProvider = new FilesystemTestResourceProvider(); tempResourceProvider.addAllRecursively(tempFileList); TestModel tempModel = TestModel.loadTestModel(tempResourceProvider, false, null); boolean tempKeepFiles = "true".equals(System.getProperty("keepFiles")); try { if (tempKeepFiles) { tempXmlFile = new File(getTempDir(), aSuiteName + ".xml"); } else { tempXmlFile = File.createTempFile("integrityJUnit", ".xml"); } TestRunnerCallback tempCallback = new CompoundTestRunnerCallback(new ConsoleTestCallback(), new XmlWriterTestCallback(getClass().getClassLoader(), tempXmlFile, "Integrity JUnit Testing", TransformHandling.NO_TRANSFORM, false)); TestRunner tempRunner = tempModel.initializeTestRunner(tempCallback, getParameterizedConstantValues(), null, null, null, null); tempRunner.run(tempModel.getSuiteByName(aSuiteName), tempModel.getVariantByName(aVariantName), false); tempRunner.shutdown(true); SAXBuilder tempBuilder = new SAXBuilder(false); return tempBuilder.build(tempXmlFile); } finally { if (tempKeepFiles) { System.out.println("Kept result file " + tempXmlFile.getAbsolutePath()); } else { if (tempXmlFile != null) { tempXmlFile.delete(); } } } } protected Map<String, String> getParameterizedConstantValues() { return null; } /** * Checks whether a given document matches its reference document. The name of the reference doc is determined by * the root suite name in the given doc and the reference XML dir {@link #REFERENCE_RESULT_DIRECTORY}. * * @param aDoc * the document to compare * @throws JDOMException * @throws IOException */ protected void assertDocumentMatchesReference(Document aDoc) throws JDOMException, IOException { assertNotNull(aDoc); String tempRootSuiteName = aDoc.getRootElement().getChild("suite").getAttribute("name").getValue(); SAXBuilder tempBuilder = new SAXBuilder(false); Document tempRef = tempBuilder.build(new File(REFERENCE_RESULT_DIRECTORY + tempRootSuiteName + ".xml")); removeDurationsAndTimes(aDoc.getRootElement()); removeObjectIDs(aDoc.getRootElement()); rempveStackTraces(aDoc.getRootElement()); removeDurationsAndTimes(tempRef.getRootElement()); removeObjectIDs(tempRef.getRootElement()); rempveStackTraces(tempRef.getRootElement()); ByteArrayOutputStream tempDocStream = new ByteArrayOutputStream(); ByteArrayOutputStream tempRefStream = new ByteArrayOutputStream(); XMLOutputter tempSerializer = new XMLOutputter(Format.getCompactFormat()); tempSerializer.output(aDoc, tempDocStream); tempSerializer.output(tempRef, tempRefStream); boolean tempArraysEqual = Arrays.equals(tempDocStream.toByteArray(), tempRefStream.toByteArray()); if (!tempArraysEqual) { System.out.println("--- Suite " + tempRootSuiteName + " failed comparison to reference data!"); System.out.print("Reference: "); System.out.println(new String(tempRefStream.toByteArray(), "UTF-8")); System.out.print("Actual: "); System.out.println(new String(tempDocStream.toByteArray(), "UTF-8")); } assertTrue(tempArraysEqual); } /** * Checks whether an exception that is expected to be thrown is actually thrown. * * @param aRunnable * the runnable to execute * @param aReferenceExceptionClass * the exception class to expect (optional) * @param aReferenceMessage * the exception message to expect (optional) * @param aReferenceMessagePattern * a pattern to match the message against (optional) */ protected void assertExceptionIsThrown(RunnableWithException aRunnable, Class<? extends Exception> aReferenceExceptionClass, String aReferenceMessage, Pattern aReferenceMessagePattern) { try { aRunnable.run(); } catch (Throwable exc) { if (aReferenceExceptionClass != null) { assertTrue(aReferenceExceptionClass.isAssignableFrom(exc.getClass())); } if (aReferenceMessage != null) { assertEquals(aReferenceMessage, exc.getMessage()); } if (aReferenceMessagePattern != null) { Matcher tempMatcher = aReferenceMessagePattern.matcher(exc.getMessage()); assertTrue(tempMatcher.matches()); } return; } // We expect an exception assertTrue("There was no exception, although one was expected", false); } private void removeDurationsAndTimes(Element anElement) throws JDOMException { clearAttribute(anElement, "duration"); clearAttribute(anElement, "timestamp"); clearAttribute(anElement, "isotimestamp"); for (Object tempChild : anElement.getChildren()) { if (tempChild instanceof Element) { removeDurationsAndTimes((Element) tempChild); } } } private void rempveStackTraces(Element anElement) throws JDOMException { Attribute tempTrace = anElement.getAttribute("exceptionTrace"); if (tempTrace != null) { tempTrace.setValue("STACKTRACE"); } for (Object tempChild : anElement.getChildren()) { if (tempChild instanceof Element) { rempveStackTraces((Element) tempChild); } } } private void clearAttribute(Element anElement, String anAttributeName) { Attribute tempAttr = anElement.getAttribute(anAttributeName); if (tempAttr != null) { tempAttr.setValue(""); } } private void removeObjectIDs(Element anElement) throws JDOMException { for (Object tempAttributeObj : anElement.getAttributes()) { Attribute tempAttribute = (Attribute) tempAttributeObj; Matcher tempMatcher = OBJECT_ID_PATTERN.matcher(tempAttribute.getValue()); if (tempMatcher.matches()) { tempAttribute.setValue(tempMatcher.group(1) + "00000000"); } } for (Object tempChild : anElement.getChildren()) { if (tempChild instanceof Element) { removeObjectIDs((Element) tempChild); } } } /** * Buffer for the temporary file dir. */ private static File temporaryFileDirectory; private static File getTempDir() throws IOException { if (temporaryFileDirectory == null) { File tempFile = File.createTempFile("integrityJUnit", ".xml"); temporaryFileDirectory = tempFile.getParentFile(); tempFile.delete(); } return temporaryFileDirectory; } /** * Special runnable which declares to throw {@link Exception}. * * * @author YOUR_NAME_HERE - initial API and implementation * */ public interface RunnableWithException { /** * The actual code. * * @throws Exception */ void run() throws Exception; } }