Merge commit '3b5069d' into develop
[simantics/platform.git] / bundles / org.simantics.tests.modelled.ui / src / org / simantics / tests / modelled / ui / STSTestSuiteModel.java
1 package org.simantics.tests.modelled.ui;\r
2 \r
3 import java.io.BufferedReader;\r
4 import java.io.StringReader;\r
5 import java.util.ArrayList;\r
6 import java.util.Collection;\r
7 import java.util.Collections;\r
8 import java.util.List;\r
9 import java.util.regex.Pattern;\r
10 import java.util.regex.PatternSyntaxException;\r
11 \r
12 import org.eclipse.swt.graphics.Image;\r
13 import org.simantics.Simantics;\r
14 import org.simantics.databoard.Bindings;\r
15 import org.simantics.db.ReadGraph;\r
16 import org.simantics.db.Resource;\r
17 import org.simantics.db.common.request.ReadRequest;\r
18 import org.simantics.db.exception.DatabaseException;\r
19 import org.simantics.layer0.Layer0;\r
20 import org.simantics.scl.compiler.commands.CommandSession;\r
21 import org.simantics.scl.compiler.commands.TestScriptExecutor;\r
22 import org.simantics.scl.compiler.module.Module;\r
23 import org.simantics.scl.compiler.module.coverage.CombinedCoverage;\r
24 import org.simantics.scl.compiler.module.coverage.CoverageBuilder;\r
25 import org.simantics.scl.compiler.module.coverage.CoverageUtils;\r
26 import org.simantics.scl.compiler.module.options.ModuleCompilationOptions;\r
27 import org.simantics.scl.compiler.module.options.ModuleCompilationOptionsAdvisor;\r
28 import org.simantics.scl.compiler.module.repository.ModuleRepository;\r
29 import org.simantics.scl.compiler.runtime.RuntimeModule;\r
30 import org.simantics.scl.osgi.SCLOsgi;\r
31 import org.simantics.scl.runtime.reporting.AbstractSCLReportingHandler;\r
32 import org.simantics.tests.modelled.ontology.TestsResource;\r
33 \r
34 public class STSTestSuiteModel {\r
35 \r
36     static class STSTest {\r
37         \r
38         private final Resource test;\r
39         private final STSSuite parent;\r
40         private final String definition;\r
41         private final String name;\r
42         private boolean executed = false;\r
43         private long duration;\r
44         private boolean failed = false;\r
45         private boolean isRunning = false;\r
46         private List<String> output = new ArrayList<>();\r
47         private CombinedCoverage coverage;\r
48         private int priority;\r
49         \r
50         public STSTest(Resource test, STSSuite parent, String definition, String name, int executionPrioprity) {\r
51             this.test = test;\r
52             this.parent = parent;\r
53             this.definition = definition;\r
54             this.name = name;\r
55             this.priority = executionPrioprity;\r
56         }\r
57         \r
58         public String getName() {\r
59             return name;\r
60         }\r
61         \r
62         public String getLabel() {\r
63             StringBuilder sb = new StringBuilder();\r
64             sb.append(name);\r
65             if (executed || failed)\r
66                 sb.append(" (").append(duration).append(" ms)");\r
67             return sb.toString();\r
68         }\r
69         \r
70         public String getDefinition() {\r
71             return definition;\r
72         }\r
73 \r
74         public STSSuite getParent() {\r
75             return parent;\r
76         }\r
77 \r
78         public void execute(CommandSession session) {\r
79             isRunning = true;\r
80             \r
81             TestScriptExecutor executor = new TestScriptExecutor(session, new BufferedReader(new StringReader(definition)), new AbstractSCLReportingHandler() {\r
82                 \r
83                 @Override\r
84                 public void print(String text) {\r
85                     appendOutput(text + "\n");\r
86                 }\r
87                 \r
88                 @Override\r
89                 public void printCommand(String command) {\r
90                     appendOutput("> " + command + "\n");\r
91                 }\r
92                 \r
93                 @Override\r
94                 public void printError(String error) {\r
95                     appendOutput(error + "\n");\r
96                 }\r
97             });\r
98             long start = System.currentTimeMillis();\r
99             try {\r
100                 if (parent != null)\r
101                     parent.startedCount++;\r
102                 executor.execute();\r
103                 executed = true;\r
104             } catch (Throwable t) {\r
105                 t.printStackTrace();\r
106                 if (parent != null)\r
107                     parent.failureCount++;\r
108                 failed = true;\r
109             } finally {\r
110                 isRunning = false;\r
111                 long end = System.currentTimeMillis();\r
112                 duration = end - start;\r
113             }\r
114 \r
115         }\r
116 \r
117         protected void appendOutput(String text) {\r
118             output.add(text);\r
119         }\r
120 \r
121         public List<String> getOutput() {\r
122             return output;\r
123         }\r
124 \r
125         public void setCoverage(CombinedCoverage coverage) {\r
126             this.coverage = coverage;\r
127         }\r
128         \r
129         public CombinedCoverage getCoverage() {\r
130             return coverage;\r
131         }\r
132         \r
133         @Override\r
134         public String toString() {\r
135             return name + " [priority=" + priority + ", executed=" + executed + ", duration=" + duration + "]";\r
136         }\r
137     }\r
138 \r
139     static class STSSuite {\r
140         \r
141         private List<Pattern> moduleNameFilterPatterns = new ArrayList<>();\r
142         private final Resource suite;\r
143         private final String name;\r
144         private STSTest[] children;\r
145         private int startedCount;\r
146         private int errorCount;\r
147         private int failureCount;\r
148         private CoverageBuilder coverageBuilder;\r
149         \r
150         public STSSuite(Resource suite, String name, String moduleNameFilter) {\r
151             this.suite = suite;\r
152             this.name = name;\r
153             for (String s : moduleNameFilter.split(",")) {\r
154                 try {\r
155                     s = s.trim().replaceAll("\\*", "\\\\w*").toLowerCase();\r
156                     moduleNameFilterPatterns.add(Pattern.compile(s));\r
157                 } catch (PatternSyntaxException e) {\r
158                     e.printStackTrace();\r
159                 }\r
160             }\r
161         }\r
162 \r
163         public void children(STSTest[] children) {\r
164             this.children = children;\r
165         }\r
166 \r
167         public STSTest[] getChildren() {\r
168             return children;\r
169         }\r
170 \r
171         public String getName() {\r
172             return name;\r
173         }\r
174 \r
175         public String getLabel() {\r
176             StringBuilder sb = new StringBuilder();\r
177             sb.append(name);\r
178             long totalTime = 0; \r
179             if (children != null) {\r
180                 for (STSTest test : children) {\r
181                     if (test.executed || test.failed) {\r
182                         totalTime += test.duration;\r
183                     }\r
184                 }\r
185             }\r
186             if (totalTime != 0)\r
187                 sb.append(" (").append(totalTime).append(" ms)");\r
188             return sb.toString();\r
189         }\r
190 \r
191         public boolean isRunning() {\r
192             boolean running = false;\r
193             if (children != null) {\r
194                 for (STSTest test: children) {\r
195                     if (test.isRunning) {\r
196                         running = true;\r
197                         break;\r
198                     }\r
199                 }\r
200             }\r
201             return running;\r
202         }\r
203 \r
204         public boolean executed() {\r
205             boolean executed = true;\r
206             if (children != null) {\r
207                 for (STSTest test: children) {\r
208                     if (!test.executed) {\r
209                         executed = false;\r
210                         break;\r
211                     }\r
212                 }\r
213             }\r
214             return executed;\r
215         }\r
216 \r
217         public boolean failed() {\r
218             boolean failed = false;\r
219             if (children != null) {\r
220                 for (STSTest test: children) {\r
221                     if (test.failed) {\r
222                         failed = true;\r
223                         break;\r
224                     }\r
225                 }\r
226             }\r
227             return failed;\r
228         }\r
229         \r
230         public void addCoverage(List<Module> modules) {\r
231             if (coverageBuilder == null) {\r
232                 coverageBuilder = new CoverageBuilder();\r
233             }\r
234             for (Module module : modules)\r
235                 coverageBuilder.addCoverage(module, true);\r
236         }\r
237 \r
238         public CombinedCoverage getCoverage() {\r
239             if (coverageBuilder == null)\r
240                 return null;\r
241             return coverageBuilder.getCoverage();\r
242         }\r
243     }\r
244 \r
245     \r
246     private STSSuite suite;\r
247     private STSTest test;\r
248     private final List<STSExecutionListener> listeners = new ArrayList<>();\r
249     \r
250     public STSTestSuiteModel() {\r
251     }\r
252     \r
253     public void addListener(STSExecutionListener listener) {\r
254         listeners.add(listener);\r
255     }\r
256     \r
257     public void removeListener(STSExecutionListener listener) {\r
258         listeners.remove(listener);\r
259     }\r
260 \r
261     public Object[] getElements() {\r
262         if (suite != null)\r
263             return new Object[] {suite};\r
264         else if (test != null)\r
265             return new Object[] {test};\r
266         else return null;\r
267     }\r
268 \r
269     public void execute() {\r
270         \r
271         ModuleRepository repo = new ModuleRepository(SCLOsgi.SOURCE_REPOSITORY);\r
272         if (suite != null) {\r
273             repo.setAdvisor(new ModuleCompilationOptionsAdvisor() {\r
274                 \r
275                 @Override\r
276                 public ModuleCompilationOptions getOptions(String moduleName) {\r
277                     boolean coverage = false;\r
278                     for (Pattern p : suite.moduleNameFilterPatterns) {\r
279                         if (p.matcher(moduleName.toLowerCase()).find()) {\r
280                             coverage = true;\r
281                             break;\r
282                         }\r
283                     }\r
284                     return new ModuleCompilationOptions(coverage);\r
285                 }\r
286             });\r
287         }\r
288         CommandSession session = new CommandSession(repo, null);\r
289         if (suite != null) {\r
290             executeSuite(session);\r
291         } else if (test != null) {\r
292             executeTest(session);\r
293         }\r
294     }\r
295     \r
296     private void testExecuted() {\r
297         listeners.forEach(listener -> {\r
298             listener.testExecuted();\r
299         });\r
300     }\r
301     \r
302     private void executeSuite(CommandSession session) {\r
303         \r
304         for (STSTest test : suite.getChildren()) {\r
305             test.execute(session);\r
306             \r
307             Collection<RuntimeModule> runtimeModules = session.getRuntimeEnvironment().getRuntimeModules();\r
308             List<Module> modules = new ArrayList<>(runtimeModules.size());\r
309             for (RuntimeModule module : runtimeModules) {\r
310                 for (Pattern p : suite.moduleNameFilterPatterns) {\r
311                     if (p.matcher(module.getModule().getName().toLowerCase()).find()) {\r
312                         modules.add(module.getModule());\r
313                     }\r
314                 }\r
315             }\r
316             test.setCoverage(CoverageUtils.getCoverage(modules));\r
317             suite.addCoverage(modules);\r
318             \r
319             CoverageUtils.resetCoverage(modules);\r
320             \r
321             testExecuted();\r
322         }\r
323 \r
324     }\r
325     \r
326     private void executeTest(CommandSession session) {\r
327         \r
328         test.execute(session);\r
329         testExecuted();\r
330         \r
331         Collection<RuntimeModule> runtimeModules = session.getRuntimeEnvironment().getRuntimeModules();\r
332         List<Module> modules = new ArrayList<>(runtimeModules.size());\r
333         for (RuntimeModule module : runtimeModules) {\r
334             modules.add(module.getModule());\r
335         }\r
336         test.setCoverage(CoverageUtils.getCoverage(modules));\r
337         \r
338         CoverageUtils.resetCoverage(modules);\r
339 \r
340     }\r
341     \r
342 \r
343     public boolean hasChildren(Object element) {\r
344         if (element instanceof STSTest) {\r
345             return false;\r
346         } else if (element instanceof STSSuite) {\r
347             STSSuite suite = (STSSuite) element;\r
348             return (suite.getChildren() != null ? suite.getChildren().length > 0 : false);\r
349         } else {\r
350             throw new IllegalArgumentException(element.toString());\r
351         }\r
352     }\r
353 \r
354     public Object getParent(Object element) {\r
355         if (element instanceof STSTest) {\r
356             return ((STSTest) element).getParent();\r
357         } else if (element instanceof STSSuite) {\r
358             return null;\r
359         } else {\r
360             throw new IllegalArgumentException(element.toString());\r
361         }\r
362     }\r
363 \r
364     public Object[] getChildren(Object parentElement) {\r
365         if (parentElement instanceof STSTest) {\r
366             return null;\r
367         } else if (parentElement instanceof STSSuite) {\r
368             STSSuite suite = (STSSuite) parentElement;\r
369             return suite.getChildren();\r
370         } else {\r
371             throw new IllegalArgumentException(parentElement.toString());\r
372         }\r
373     }\r
374 \r
375     public String getText(Object element) {\r
376         if (element instanceof STSTest)\r
377             return ((STSTest)element).getLabel();\r
378         else if (element instanceof STSSuite)\r
379             return ((STSSuite)element).getLabel();\r
380         else\r
381             throw new IllegalArgumentException(element.toString());\r
382     }\r
383 \r
384     public Image getImage(Object element) {\r
385         if (element instanceof STSSuite) {\r
386             STSSuite suite = (STSSuite) element;\r
387             if (suite.isRunning())\r
388                 return STSTestSuiteProvider.suiteRunningIcon;\r
389             else if (suite.executed())\r
390                 return STSTestSuiteProvider.suiteOkIcon;\r
391             else if (suite.failed())\r
392                 return STSTestSuiteProvider.suiteFailIcon;\r
393             else\r
394                 return STSTestSuiteProvider.suiteIcon;\r
395         } else if (element instanceof STSTest) {\r
396             STSTest test = (STSTest) element;\r
397             if (test.isRunning)\r
398                 return STSTestSuiteProvider.testRunningIcon;\r
399             else if (test.executed)\r
400                 return STSTestSuiteProvider.testOkIcon;\r
401             else if (test.failed)\r
402                 return STSTestSuiteProvider.testFailIcon;\r
403             else\r
404                 return STSTestSuiteProvider.testIcon;\r
405         }\r
406         return null;\r
407     }\r
408 \r
409     public void updateInput(Resource root) {\r
410         suite = null;\r
411         test = null;\r
412         try {\r
413             Simantics.getSession().syncRequest(new ReadRequest() {\r
414                 \r
415                 @Override\r
416                 public void run(ReadGraph graph) throws DatabaseException {\r
417                     Layer0 L0 = Layer0.getInstance(graph);\r
418                     TestsResource TESTS = TestsResource.getInstance(graph);\r
419                     if (graph.isInstanceOf(root, TESTS.STSTest)) {\r
420                         String testName = graph.getRelatedValue2(root, L0.HasName, Bindings.STRING);\r
421                         String definition = graph.getRelatedValue2(root, TESTS.STSTest_definition, Bindings.STRING);\r
422                         Integer executionPrioprity = graph.getRelatedValue2(root, TESTS.STSTest_executionPriority, Bindings.INTEGER);\r
423                         test = new STSTest(root, null, definition, testName, executionPrioprity);\r
424                     } else if (graph.isInstanceOf(root, TESTS.STSSuite)) {\r
425                         String suiteName = graph.getRelatedValue2(root, L0.HasName, Bindings.STRING);\r
426                         String moduleNameFilter = graph.getPossibleRelatedValue2(root, TESTS.STSSuite_moduleNameFilter, Bindings.STRING);\r
427                         suite = new STSSuite(root, suiteName, moduleNameFilter);\r
428                         List<STSTest> tests = new ArrayList<>();\r
429                         for (Resource test : graph.getObjects(root, L0.ConsistsOf)) {\r
430                             String testName = graph.getRelatedValue2(test, L0.HasName, Bindings.STRING);\r
431                             String definition = graph.getRelatedValue2(test, TESTS.STSTest_definition, Bindings.STRING);\r
432                             Integer executionPrioprity = graph.getRelatedValue2(test, TESTS.STSTest_executionPriority, Bindings.INTEGER);\r
433                             tests.add(new STSTest(test, suite, definition, testName, executionPrioprity));\r
434                         }\r
435                         Collections.sort(tests, (o1, o2) -> {\r
436                             if (o1.priority < o2.priority)\r
437                                 return -1;\r
438                             if (o1.priority > o2.priority)\r
439                                 return 1;\r
440                             return 0;\r
441                         });\r
442                         suite.children(tests.toArray(new STSTest[tests.size()]));\r
443                     } else {\r
444                         throw new IllegalArgumentException(root.toString());\r
445                     }\r
446                 }\r
447             });\r
448         } catch (DatabaseException e) {\r
449             e.printStackTrace();\r
450         }\r
451     }\r
452 \r
453     public List<String> getOutput(Object element) {\r
454         if (element instanceof STSTest) {\r
455             STSTest test = (STSTest) element;\r
456             return test.getOutput();\r
457         }\r
458         return Collections.emptyList();\r
459     }\r
460 \r
461     public int getStartedCount() {\r
462         if (suite != null)\r
463             return suite.startedCount;\r
464         else\r
465             return 0;\r
466     }\r
467 \r
468     public int getIgnoredCount() {\r
469         return 0;\r
470     }\r
471 \r
472     public int getTotalCount() {\r
473         if (suite != null && suite.getChildren() != null)\r
474             return suite.getChildren().length;\r
475         else if (test != null)\r
476             return 1;\r
477         else\r
478             return 0;\r
479     }\r
480 \r
481     public int getErrorCount() {\r
482         if (suite != null)\r
483             return suite.errorCount;\r
484         return 0;\r
485     }\r
486 \r
487     public int getFailureCount() {\r
488         if (suite != null)\r
489             return suite.failureCount;\r
490         return 0;\r
491     }\r
492 \r
493     public int getAssumptionFailureCount() {\r
494         return 0;\r
495     }\r
496 \r
497     public boolean isStopped() {\r
498         if (suite != null)\r
499             return !suite.isRunning();\r
500         else\r
501             return test.isRunning;\r
502     }\r
503 }\r
504 \r