1 package org.simantics.db.testing.base;
3 import java.io.IOException;
4 import java.lang.management.ManagementFactory;
5 import java.util.ArrayList;
8 import java.util.Timer;
9 import java.util.TimerTask;
11 import org.junit.Rule;
12 import org.junit.rules.TestName;
13 import org.osgi.framework.BundleContext;
14 import org.simantics.db.testing.cases.FreshDatabaseTest;
15 import org.simantics.scl.compiler.module.repository.ModuleRepository;
16 import org.simantics.scl.compiler.testing.TestRunnable;
17 import org.simantics.scl.compiler.testing.repository.TestRepository;
18 import org.simantics.scl.osgi.SCLOsgi;
19 import org.simantics.scl.osgi.internal.Activator;
20 import org.simantics.scl.osgi.internal.ServiceBasedModuleSourceRepository;
21 import org.simantics.scl.osgi.internal.ServiceBasedTestRepository;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
25 import gnu.trove.map.hash.THashMap;
28 * Utilizies {@link TestRepository} for collecting SCL tests from bundles
30 * @author Jani Simomaa
32 public class SCLScriptTestBase extends FreshDatabaseTest {
34 private static final Logger LOGGER = LoggerFactory.getLogger(SCLScriptTestBase.class);
36 private Map<String, TestRunnable> testRunnables = new THashMap<String, TestRunnable>();
38 @Rule public TestName testName = new TestName();
41 * Constructor that initially searches for all SCL test scripts and stores
42 * them into a Map for later access
44 public SCLScriptTestBase() {
46 BundleContext context = Activator.getContext();
47 List<TestRunnable> runnables = new ArrayList<TestRunnable>();
48 context.getService(context.getServiceReference(TestRepository.class)).collectTests(runnables);
49 for (TestRunnable runnable : runnables) {
50 testRunnables.put(runnable.getName(), runnable);
55 * Simplest method for running a SCL test
57 protected void test() {
62 * Executes a test case with given timeout as seconds. When time runs out one
63 * can assume a deadlock has happened. The process is killed after the timeout
64 * in order to keep the possible multiple tests running.
66 * @param timeout allowed execution time given in seconds
68 protected void test(int timeout) {
73 * Executes a test case with given timeout as seconds
75 * @param timeout allowed execution time given in seconds
77 private void testImpl(int timeout) {
78 SCLOsgi.SOURCE_REPOSITORY = new ServiceBasedModuleSourceRepository(Activator.getContext());
79 SCLOsgi.MODULE_REPOSITORY = new ModuleRepository(SCLOsgi.SOURCE_REPOSITORY);
80 SCLOsgi.TEST_REPOSITORY = new ServiceBasedTestRepository(Activator.getContext());
82 String testName = resolveTestName();
83 TestRunnable runnable = testRunnables.get(testName);
84 if (runnable == null) {
85 LOGGER.error("SCL Test Suite file (.sts) for test {} cannot be found from test repository.", testName);
89 long start = System.nanoTime();
91 LOGGER.info("Running test {} with a timeout of {} seconds", testName, timeout); //$NON-NLS-1$
92 Timer timer = new Timer();
93 timer.schedule(new TimerTask() {
97 LOGGER.info("Watchdog will kill this test process because it has been executing for over {} seconds", timeout); //$NON-NLS-1$
98 String processName = ManagementFactory.getRuntimeMXBean().getName();
99 LOGGER.info("Test Process Name: {}", processName); //$NON-NLS-1$
100 String PID = processName.split("@")[0];
101 String command = "taskkill /F /PID " + PID;
102 LOGGER.info("Running command to kill test process: {}", command); //$NON-NLS-1$
104 Runtime.getRuntime().exec(command);
105 } catch (IOException e) {
106 LOGGER.error("Failed to kill process that ran over its execution time limit of {} seconds", timeout, e);
113 long end = System.nanoTime();
114 LOGGER.info("Completed test {} execution in {} seconds", testName, String.format("%.3f", (end-start)*1e-9)); //$NON-NLS-1$
115 } catch (Exception e) {
116 LOGGER.error("Failed to run test {} runnable {}", testName, runnable, e);
121 LOGGER.info("Running test {} without timeout", testName); //$NON-NLS-1$
124 long end = System.nanoTime();
125 LOGGER.info("Completed test {} execution in {} seconds", testName, String.format("%.3f", (end-start)*1e-9)); //$NON-NLS-1$
126 } catch (Exception e) {
127 LOGGER.error("Failed to run test {} runnable {}", testName, runnable, e);
133 * Resolves the full test name based on the names of classes that extends this
134 * SCLScriptTestBase class.<br><br>
136 * For example if our tests locate in <code>sclTests/Simantics/Regression/FirstTest.sts</code>
137 * the class hierarchy would be:
140 * <li><code>SCLScriptTestBase</code>
142 * <li><code>Simantics</code>
144 * <li><code>Regression</code></li>
150 * And the script file name is the same than JUnit method name.
152 * @return full testName
154 private String resolveTestName() {
155 StringBuilder sb = new StringBuilder();
156 Class<?> clazz = this.getClass();
158 if (!(clazz.getName() == SCLScriptTestBase.class.getName())) {
159 String[] classNameParts = clazz.getName().split("\\.");
161 sb.insert(0, classNameParts[classNameParts.length - 1]);
162 clazz = clazz.getSuperclass();
164 sb.append(testName.getMethodName());
168 return sb.toString();