package org.simantics.db.testing.base; import java.io.IOException; import java.lang.management.ManagementFactory; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Timer; import java.util.TimerTask; import org.junit.Rule; import org.junit.rules.TestName; import org.osgi.framework.BundleContext; import org.simantics.db.testing.cases.FreshDatabaseTest; import org.simantics.scl.compiler.module.repository.ModuleRepository; import org.simantics.scl.compiler.testing.TestRunnable; import org.simantics.scl.compiler.testing.repository.TestRepository; import org.simantics.scl.osgi.SCLOsgi; import org.simantics.scl.osgi.internal.Activator; import org.simantics.scl.osgi.internal.ServiceBasedModuleSourceRepository; import org.simantics.scl.osgi.internal.ServiceBasedTestRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import gnu.trove.map.hash.THashMap; /** * Utilizies {@link TestRepository} for collecting SCL tests from bundles * * @author Jani Simomaa */ public class SCLScriptTestBase extends FreshDatabaseTest { private static final Logger LOGGER = LoggerFactory.getLogger(SCLScriptTestBase.class); private Map testRunnables = new THashMap(); @Rule public TestName testName = new TestName(); /** * Constructor that initially searches for all SCL test scripts and stores * them into a Map for later access */ public SCLScriptTestBase() { super(); BundleContext context = Activator.getContext(); List runnables = new ArrayList(); context.getService(context.getServiceReference(TestRepository.class)).collectTests(runnables); for (TestRunnable runnable : runnables) { testRunnables.put(runnable.getName(), runnable); } } /** * Simplest method for running a SCL test */ protected void test() { test(-1); } /** * Executes a test case with given timeout as seconds. When time runs out one * can assume a deadlock has happened. The process is killed after the timeout * in order to keep the possible multiple tests running. * * @param timeout allowed execution time given in seconds */ protected void test(int timeout) { testImpl(timeout); } /** * Executes a test case with given timeout as seconds * * @param timeout allowed execution time given in seconds */ private void testImpl(int timeout) { SCLOsgi.SOURCE_REPOSITORY = new ServiceBasedModuleSourceRepository(Activator.getContext()); SCLOsgi.MODULE_REPOSITORY = new ModuleRepository(SCLOsgi.SOURCE_REPOSITORY); SCLOsgi.TEST_REPOSITORY = new ServiceBasedTestRepository(Activator.getContext()); String testName = resolveTestName(); TestRunnable runnable = testRunnables.get(testName); if (timeout > -1) { Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { LOGGER.info("Watchdog will kill this test process because it has been executing for over {} seconds", timeout); //$NON-NLS-1$ String processName = ManagementFactory.getRuntimeMXBean().getName(); LOGGER.info("Test Process Name: {}", processName); //$NON-NLS-1$ String PID = processName.split("@")[0]; String command = "taskkill /F /PID " + PID; LOGGER.info("Running command to kill test process: {}", command); //$NON-NLS-1$ try { Runtime.getRuntime().exec(command); } catch (IOException e) { LOGGER.error("Failed to kill process that ran over its execution time limit of {} seconds", timeout, e); } } }, timeout*1000); try { runnable.run(); } catch (Exception e) { LOGGER.error("Failed to run test {} runnable {}", testName, runnable, e); } finally { timer.cancel(); } } else { try { runnable.run(); } catch (Exception e) { LOGGER.error("Failed to run test {} runnable {}", testName, runnable, e); } } } /** * Resolves the full test name based on the names of classes that extends this * SCLScriptTestBase class.

* * For example if our tests locate in sclTests/Simantics/Regression/FirstTest.sts * the class hierarchy would be: * *
    *
  • SCLScriptTestBase *
      *
    • Simantics *
        *
      • Regression
      • *
      *
    • *
    *
  • *
* And the script file name is the same than JUnit method name. * * @return full testName */ private String resolveTestName() { StringBuilder sb = new StringBuilder(); Class clazz = this.getClass(); while (true) { if (!(clazz.getName() == SCLScriptTestBase.class.getName())) { String[] classNameParts = clazz.getName().split("\\."); sb.insert(0, "/"); sb.insert(0, classNameParts[classNameParts.length - 1]); clazz = clazz.getSuperclass(); } else { sb.append(testName.getMethodName()); break; } } return sb.toString(); } }