--- /dev/null
+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 gnu.trove.map.hash.THashMap;
+
+/**
+ * Utilizies {@link TestRepository} for collecting SCL tests from bundles
+ *
+ * @author Jani
+ *
+ */
+public class SCLScriptTestBase extends FreshDatabaseTest {
+
+ private Map<String, TestRunnable> testRunnables = new THashMap<String, TestRunnable>();
+
+ @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<TestRunnable> runnables = new ArrayList<TestRunnable>();
+ 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() {
+ String processName = ManagementFactory.getRuntimeMXBean().getName();
+ System.out.println("PID: " + processName);
+ String PID = processName.split("@")[0];
+ String command = "taskkill /F /PID " + PID;
+ System.out.println("Command: " + command);
+ try {
+ Runtime.getRuntime().exec(command);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ }, timeout*1000);
+ try {
+ runnable.run();
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ timer.cancel();
+ }
+ } else {
+ try {
+ runnable.run();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * Resolves the full test name based on the names of classes that extends this
+ * SCLScriptTestBase class.<br><br>
+ *
+ * For example if our tests locate in <code>sclTests/Simantics/Regression/FirstTest.sts</code>
+ * the class hierarchy would be:
+ *
+ * <ul>
+ * <li><code>SCLScriptTestBase</code>
+ * <ul>
+ * <li><code>Simantics</code>
+ * <ul>
+ * <li><code>Regression</code></li>
+ * </ul>
+ * </li>
+ * </ul>
+ * </li>
+ * </ul>
+ * 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();
+ }
+
+}