package org.simantics.tests.modelled.ui; import java.io.BufferedReader; import java.io.StringReader; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import org.eclipse.swt.graphics.Image; import org.simantics.Simantics; import org.simantics.databoard.Bindings; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.common.request.ReadRequest; import org.simantics.db.exception.DatabaseException; import org.simantics.layer0.Layer0; import org.simantics.scl.compiler.commands.CommandSession; import org.simantics.scl.compiler.commands.TestScriptExecutor; import org.simantics.scl.compiler.module.Module; import org.simantics.scl.compiler.module.coverage.CombinedCoverage; import org.simantics.scl.compiler.module.coverage.CoverageBuilder; import org.simantics.scl.compiler.module.coverage.CoverageUtils; import org.simantics.scl.compiler.module.options.ModuleCompilationOptions; import org.simantics.scl.compiler.module.options.ModuleCompilationOptionsAdvisor; import org.simantics.scl.compiler.module.repository.ModuleRepository; import org.simantics.scl.compiler.runtime.RuntimeModule; import org.simantics.scl.osgi.SCLOsgi; import org.simantics.scl.runtime.reporting.AbstractSCLReportingHandler; import org.simantics.tests.modelled.ontology.TestsResource; public class STSTestSuiteModel { static class STSTest { private final Resource test; private final STSSuite parent; private final String definition; private final String name; private boolean executed = false; private long duration; private boolean failed = false; private boolean isRunning = false; private List output = new ArrayList<>(); private CombinedCoverage coverage; private int priority; public STSTest(Resource test, STSSuite parent, String definition, String name, int executionPrioprity) { this.test = test; this.parent = parent; this.definition = definition; this.name = name; this.priority = executionPrioprity; } public String getName() { return name; } public String getLabel() { StringBuilder sb = new StringBuilder(); sb.append(name); if (executed || failed) sb.append(" (").append(duration).append(" ms)"); return sb.toString(); } public String getDefinition() { return definition; } public STSSuite getParent() { return parent; } public void execute(CommandSession session) { isRunning = true; TestScriptExecutor executor = new TestScriptExecutor(session, new BufferedReader(new StringReader(definition)), new AbstractSCLReportingHandler() { @Override public void print(String text) { appendOutput(text + "\n"); } @Override public void printCommand(String command) { appendOutput("> " + command + "\n"); } @Override public void printError(String error) { appendOutput(error + "\n"); } }); long start = System.currentTimeMillis(); try { if (parent != null) parent.startedCount++; executor.execute(); executed = true; } catch (Throwable t) { t.printStackTrace(); if (parent != null) parent.failureCount++; failed = true; } finally { isRunning = false; long end = System.currentTimeMillis(); duration = end - start; } } protected void appendOutput(String text) { output.add(text); } public List getOutput() { return output; } public void setCoverage(CombinedCoverage coverage) { this.coverage = coverage; } public CombinedCoverage getCoverage() { return coverage; } @Override public String toString() { return name + " [priority=" + priority + ", executed=" + executed + ", duration=" + duration + "]"; } } static class STSSuite { private List moduleNameFilterPatterns = new ArrayList<>(); private final Resource suite; private final String name; private STSTest[] children; private int startedCount; private int errorCount; private int failureCount; private CoverageBuilder coverageBuilder; public STSSuite(Resource suite, String name, String moduleNameFilter) { this.suite = suite; this.name = name; for (String s : moduleNameFilter.split(",")) { try { s = s.trim().replaceAll("\\*", "\\\\w*").toLowerCase(); moduleNameFilterPatterns.add(Pattern.compile(s)); } catch (PatternSyntaxException e) { e.printStackTrace(); } } } public void children(STSTest[] children) { this.children = children; } public STSTest[] getChildren() { return children; } public String getName() { return name; } public String getLabel() { StringBuilder sb = new StringBuilder(); sb.append(name); long totalTime = 0; if (children != null) { for (STSTest test : children) { if (test.executed || test.failed) { totalTime += test.duration; } } } if (totalTime != 0) sb.append(" (").append(totalTime).append(" ms)"); return sb.toString(); } public boolean isRunning() { boolean running = false; if (children != null) { for (STSTest test: children) { if (test.isRunning) { running = true; break; } } } return running; } public boolean executed() { boolean executed = true; if (children != null) { for (STSTest test: children) { if (!test.executed) { executed = false; break; } } } return executed; } public boolean failed() { boolean failed = false; if (children != null) { for (STSTest test: children) { if (test.failed) { failed = true; break; } } } return failed; } public void addCoverage(List modules) { if (coverageBuilder == null) { coverageBuilder = new CoverageBuilder(); } for (Module module : modules) coverageBuilder.addCoverage(module, true); } public CombinedCoverage getCoverage() { if (coverageBuilder == null) return null; return coverageBuilder.getCoverage(); } } private STSSuite suite; private STSTest test; private final List listeners = new ArrayList<>(); public STSTestSuiteModel() { } public void addListener(STSExecutionListener listener) { listeners.add(listener); } public void removeListener(STSExecutionListener listener) { listeners.remove(listener); } public Object[] getElements() { if (suite != null) return new Object[] {suite}; else if (test != null) return new Object[] {test}; else return null; } public void execute() { ModuleRepository repo = new ModuleRepository(SCLOsgi.SOURCE_REPOSITORY); if (suite != null) { repo.setAdvisor(new ModuleCompilationOptionsAdvisor() { @Override public ModuleCompilationOptions getOptions(String moduleName) { boolean coverage = false; for (Pattern p : suite.moduleNameFilterPatterns) { if (p.matcher(moduleName.toLowerCase()).find()) { coverage = true; break; } } return new ModuleCompilationOptions(coverage); } }); } CommandSession session = new CommandSession(repo, null); if (suite != null) { executeSuite(session); } else if (test != null) { executeTest(session); } } private void testExecuted() { listeners.forEach(listener -> { listener.testExecuted(); }); } private void executeSuite(CommandSession session) { for (STSTest test : suite.getChildren()) { test.execute(session); Collection runtimeModules = session.getRuntimeEnvironment().getRuntimeModules(); List modules = new ArrayList<>(runtimeModules.size()); for (RuntimeModule module : runtimeModules) { for (Pattern p : suite.moduleNameFilterPatterns) { if (p.matcher(module.getModule().getName().toLowerCase()).find()) { modules.add(module.getModule()); } } } test.setCoverage(CoverageUtils.getCoverage(modules)); suite.addCoverage(modules); CoverageUtils.resetCoverage(modules); testExecuted(); } } private void executeTest(CommandSession session) { test.execute(session); testExecuted(); Collection runtimeModules = session.getRuntimeEnvironment().getRuntimeModules(); List modules = new ArrayList<>(runtimeModules.size()); for (RuntimeModule module : runtimeModules) { modules.add(module.getModule()); } test.setCoverage(CoverageUtils.getCoverage(modules)); CoverageUtils.resetCoverage(modules); } public boolean hasChildren(Object element) { if (element instanceof STSTest) { return false; } else if (element instanceof STSSuite) { STSSuite suite = (STSSuite) element; return (suite.getChildren() != null ? suite.getChildren().length > 0 : false); } else { throw new IllegalArgumentException(element.toString()); } } public Object getParent(Object element) { if (element instanceof STSTest) { return ((STSTest) element).getParent(); } else if (element instanceof STSSuite) { return null; } else { throw new IllegalArgumentException(element.toString()); } } public Object[] getChildren(Object parentElement) { if (parentElement instanceof STSTest) { return null; } else if (parentElement instanceof STSSuite) { STSSuite suite = (STSSuite) parentElement; return suite.getChildren(); } else { throw new IllegalArgumentException(parentElement.toString()); } } public String getText(Object element) { if (element instanceof STSTest) return ((STSTest)element).getLabel(); else if (element instanceof STSSuite) return ((STSSuite)element).getLabel(); else throw new IllegalArgumentException(element.toString()); } public Image getImage(Object element) { if (element instanceof STSSuite) { STSSuite suite = (STSSuite) element; if (suite.isRunning()) return STSTestSuiteProvider.suiteRunningIcon; else if (suite.executed()) return STSTestSuiteProvider.suiteOkIcon; else if (suite.failed()) return STSTestSuiteProvider.suiteFailIcon; else return STSTestSuiteProvider.suiteIcon; } else if (element instanceof STSTest) { STSTest test = (STSTest) element; if (test.isRunning) return STSTestSuiteProvider.testRunningIcon; else if (test.executed) return STSTestSuiteProvider.testOkIcon; else if (test.failed) return STSTestSuiteProvider.testFailIcon; else return STSTestSuiteProvider.testIcon; } return null; } public void updateInput(Resource root) { suite = null; test = null; try { Simantics.getSession().syncRequest(new ReadRequest() { @Override public void run(ReadGraph graph) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); TestsResource TESTS = TestsResource.getInstance(graph); if (graph.isInstanceOf(root, TESTS.STSTest)) { String testName = graph.getRelatedValue2(root, L0.HasName, Bindings.STRING); String definition = graph.getRelatedValue2(root, TESTS.STSTest_definition, Bindings.STRING); Integer executionPrioprity = graph.getRelatedValue2(root, TESTS.STSTest_executionPriority, Bindings.INTEGER); test = new STSTest(root, null, definition, testName, executionPrioprity); } else if (graph.isInstanceOf(root, TESTS.STSSuite)) { String suiteName = graph.getRelatedValue2(root, L0.HasName, Bindings.STRING); String moduleNameFilter = graph.getPossibleRelatedValue2(root, TESTS.STSSuite_moduleNameFilter, Bindings.STRING); suite = new STSSuite(root, suiteName, moduleNameFilter); List tests = new ArrayList<>(); for (Resource test : graph.getObjects(root, L0.ConsistsOf)) { String testName = graph.getRelatedValue2(test, L0.HasName, Bindings.STRING); String definition = graph.getRelatedValue2(test, TESTS.STSTest_definition, Bindings.STRING); Integer executionPrioprity = graph.getRelatedValue2(test, TESTS.STSTest_executionPriority, Bindings.INTEGER); tests.add(new STSTest(test, suite, definition, testName, executionPrioprity)); } Collections.sort(tests, (o1, o2) -> { if (o1.priority < o2.priority) return -1; if (o1.priority > o2.priority) return 1; return 0; }); suite.children(tests.toArray(new STSTest[tests.size()])); } else { throw new IllegalArgumentException(root.toString()); } } }); } catch (DatabaseException e) { e.printStackTrace(); } } public List getOutput(Object element) { if (element instanceof STSTest) { STSTest test = (STSTest) element; return test.getOutput(); } return Collections.emptyList(); } public int getStartedCount() { if (suite != null) return suite.startedCount; else return 0; } public int getIgnoredCount() { return 0; } public int getTotalCount() { if (suite != null && suite.getChildren() != null) return suite.getChildren().length; else if (test != null) return 1; else return 0; } public int getErrorCount() { if (suite != null) return suite.errorCount; return 0; } public int getFailureCount() { if (suite != null) return suite.failureCount; return 0; } public int getAssumptionFailureCount() { return 0; } public boolean isStopped() { if (suite != null) return !suite.isRunning(); else return test.isRunning; } }