/* * #%~ * Combinatorial Testing Runtime * %% * Copyright (C) 2008 - 2014 Overture * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-3.0.html>. * #~% */ package org.overture.ct.ctruntime.tests; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.net.ServerSocket; import java.util.List; import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPathExpressionException; import org.apache.commons.io.FileUtils; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.overture.ast.lex.Dialect; import org.overture.ast.lex.LexLocation; import org.overture.config.Settings; import org.overture.ct.ctruntime.TraceRunnerMain; import org.overture.ct.ctruntime.utils.CtHelper; import org.overture.ct.ctruntime.utils.CtHelper.CtTestData; import org.overture.ct.ctruntime.utils.Data; import org.overture.ct.ctruntime.utils.TraceResult; import org.overture.ct.ctruntime.utils.TraceResultReader; import org.overture.test.framework.Properties; import org.overture.test.framework.TestResourcesResultTestCase4; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.xml.sax.SAXException; @SuppressWarnings("rawtypes") public abstract class CtTestCaseBase extends TestResourcesResultTestCase4 { private static final String TESTS_CT_RUNTIME_PROPERTY_PREFIX = "tests.ctruntime.override."; // The socket is used to communicate with the trace interpreter protected ServerSocket socket; protected static final int SOCKET_TIMEOUT = 0; private static final int FROM_PORT = 10000; private static final int TO_PORT = 50000; // Used a fixed trace name for simplicity protected static final String TRACE_NAME = "T1"; public static final String TRACE_OUTPUT_FOLDER = "target/trace-output/"; private File traceFolder; private CtTestData testdata; public CtTestCaseBase() { super(); } public CtTestCaseBase(File file, File traceFolder, CtTestData args) { super(file); this.testdata = args; this.traceFolder = traceFolder; } @Before public void internalSetup() throws Exception { setUp(); } abstract public void setUp() throws Exception; @After public void tearDown() throws Exception { try { if (this.socket != null) { this.socket.close(); } } catch (Exception e) { } } @Test public void test() throws Exception { if (file == null) { return; } try { configureResultGeneration(); File actualResultsFile = computeActualResults(TRACE_NAME); if (Properties.recordTestResults) { try { File resultFile = createResultFile(file.getAbsolutePath()); resultFile.getParentFile().mkdirs(); // Overwrite result file FileUtils.copyFile(actualResultsFile, resultFile); } catch (Exception e) { Assert.fail("The produced results could not be stored: " + e.getMessage()); } } else { File resultFile = getResultFile(file.getAbsolutePath()); TraceResultReader reader = new TraceResultReader(); List<TraceResult> actualResults = reader.read(actualResultsFile); Assert.assertTrue("No result file found for test: " + file + "\n\n" + actualResults, resultFile.exists()); List<TraceResult> expectedResults = reader.read(resultFile); Assert.assertTrue(expectedResults.size() == actualResults.size()); int size = expectedResults.size(); for (int i = 0; i < size; i++) { TraceResult expected = expectedResults.get(i); TraceResult actual = actualResults.get(i); Assert.assertTrue("Actual results differs from expected results for test: " + file + "\nExpected: " + expectedResults + "\n\nActual: " + actualResults, expected.equals(actual)); } } } finally { unconfigureResultGeneration(); } } @Override protected File createResultFile(String filename) { return new File(filename + ".result"); } @Override protected File getResultFile(String filename) { return new File(filename + ".result"); } public File computeActualResults(final String spec) throws IOException, XPathExpressionException, SAXException, ParserConfigurationException { int port =findAvailablePort(FROM_PORT, TO_PORT); socket = new ServerSocket(port); socket.setSoTimeout(SOCKET_TIMEOUT); final Data data = new Data(); traceFolder.mkdirs(); String traceName = "T1"; String actualOutputFileName = (Settings.dialect == Dialect.VDM_SL ? "DEFAULT-" : "Entry-") + traceName + ".xml"; final File actualOutputFile = new File(traceFolder, actualOutputFileName); CtHelper testHelper = new CtHelper(); Thread t = testHelper.consCtClientThread(socket, data); t.setDaemon(false); t.start(); TraceRunnerMain.USE_SYSTEM_EXIT = false; this.testdata.port = port; String[] args = testHelper.buildArgs(Settings.dialect, Settings.release, testdata); TraceRunnerMain.main(args); final String message = data.getMessage(); Assert.assertTrue("Test did not succed. Are you sure that it contains "+ (Settings.dialect==Dialect.VDM_SL?"'DEFAULT`T1'" : "'Entry`T1'"), message.contains("status=\"completed\" progress=\"100\"")); return actualOutputFile; } @Override public void encodeResult(Object result, Document doc, Element resultElement) { } @Override public Object decodeResult(Node node) { return null; } @Override protected boolean assertEqualResults(Object expected, Object actual, PrintWriter out) { return false; } protected void configureResultGeneration() { LexLocation.absoluteToStringLocation = false; if (System.getProperty(TESTS_CT_RUNTIME_PROPERTY_PREFIX + "all") != null || getPropertyId() != null && System.getProperty(TESTS_CT_RUNTIME_PROPERTY_PREFIX + getPropertyId()) != null) { Properties.recordTestResults = true; } } protected void unconfigureResultGeneration() { Properties.recordTestResults = false; } protected abstract String getPropertyId(); public static int findAvailablePort(int fromPort, int toPort) { if (fromPort > toPort) { throw new IllegalArgumentException("startPortShouldBeLessThanOrEqualToEndPort"); } int port = fromPort; ServerSocket socket = null; while (port <= toPort) { try { socket = new ServerSocket(port); return port; } catch (IOException e) { ++port; } finally { if (socket != null) { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } return -1; } }