diff --git a/OfflineMBT.setup b/OfflineMBT.setup index 7eee055a..77fadeb0 100644 --- a/OfflineMBT.setup +++ b/OfflineMBT.setup @@ -398,7 +398,7 @@ + url="https://TNO.github.io/XPlus/nightly/"/> OfflineMBT - Maven Dependencies diff --git a/bundles/nl.asml.matala.generator.fast/src/nl/asml/matala/generator/bpmn/FromConcreteToBpmn.xtend b/bundles/nl.asml.matala.generator.fast/src/nl/asml/matala/generator/bpmn/FromConcreteToBpmn.xtend index 4b021b2e..c56106d5 100644 --- a/bundles/nl.asml.matala.generator.fast/src/nl/asml/matala/generator/bpmn/FromConcreteToBpmn.xtend +++ b/bundles/nl.asml.matala.generator.fast/src/nl/asml/matala/generator/bpmn/FromConcreteToBpmn.xtend @@ -26,6 +26,7 @@ class FromConcreteToBpmn extends AbstractGenerator implements IStandardProjectGe val absTspecFsa = fsa.createFolderAccess(FOLDER_ABSTRACT_TSPEC) val absTspecURI = conTspecRes.URI.trimFileExtension.appendFileExtension('atspec') val absTspecRes = absTspecFsa.loadResource(absTspecURI.lastSegment, conTspecRes.resourceSet) + absTspecRes.checkResource() // Generate bpmn for atspec val fromAbstractToBpmn = new FromAbstractToBpmn() diff --git a/bundles/nl.asml.matala.product.tests/resources/expected/gettest/CPNServer/gettest/gettest.py b/bundles/nl.asml.matala.product.tests/resources/expected/gettest/CPNServer/gettest/gettest.py index a33f3838..ac39b99a 100644 --- a/bundles/nl.asml.matala.product.tests/resources/expected/gettest/CPNServer/gettest/gettest.py +++ b/bundles/nl.asml.matala.product.tests/resources/expected/gettest/CPNServer/gettest/gettest.py @@ -10,10 +10,12 @@ if __package__ is None or __package__ == '': from gettest_TestSCN import TestSCN, Step, Tests, Constraint, CEntry from gettest_data import Data + from gettest_reporting import get_reporting, initialize_reporting, Location from gettest_Simulation import Simulation, simulate else: from .gettest_TestSCN import TestSCN, Step, Tests, Constraint, CEntry from .gettest_data import Data + from .gettest_reporting import get_reporting, initialize_reporting, Location from .gettest_Simulation import Simulation, simulate import subprocess import copy @@ -233,7 +235,8 @@ def initializeTestGeneration(self): if k + "_" +elm.__repr__() in self.map_transition_modes_to_name: print("WARN: duplicate modes detected for same transition.") print(k + "_" +elm.__repr__()) - print("WARN: references to the above transitions are ambigous!") + print("WARN: references to the above transitions are ambiguous!") + get_reporting().warning("Duplicate modes detected for same transition, Check References in Details", details=f"{k}_{str.join('\n',[str(s) for s in elm.items()])}") self.map_transition_modes_to_name[k + "_" +elm.__repr__()] = k + "_" + str(cnt) # self.map_transition_modes_to_name[k + "_" + pprint.pformat(elm.items(), width=60, compact=True,depth=5)] = k + "_" + str(cnt) cnt = cnt + 1 @@ -252,7 +255,7 @@ def generateTestCases(self): for entry in pn.visitedTList: # txt = '' if entry: - _test_scn = TestSCN(self.map_transition_assert, self.constraint_dict, self.tr_assert_ref_dict) + _test_scn = TestSCN(pspec_path, self.map_transition_assert, self.constraint_dict, self.tr_assert_ref_dict) idx = idx + 1 j = 0 for step in entry: @@ -340,103 +343,127 @@ def copy(self, name=None): type=bool, default=False, help="Disable simulation") - + + parser.add_argument("-srfile","--status_report_file", + type=Path, + default=None, + help="The path to where the status report will be saved") + + parser.add_argument("-pspath","--pspec_path", + type=str, + default="", + help="The relatve path to the pspec file to be used for test generation") + p = parser.parse_args() p.tspec_dir.mkdir(exist_ok=True) p.plantuml_dir.mkdir(exist_ok=True) - - a = datetime.datetime.now() - pn = gettestModel() - print("[INFO] Loaded CPN model.") - # pn.n.draw('net-gv-graph.png') - s = StateGraph(pn.n) - # s.build() - # s.draw('test-gv-graph.png') - # print(" Finished Generation, writing to file.. ") - print("[INFO] Starting Reachability Graph Generation") - # pn.generateScenarios(s,0,[],[],[],0,300) - sys.setrecursionlimit(400) - pn.generateSCN() - print('Num Tests: ', pn.numTestCases) - print("[INFO] Finished.") - b = datetime.datetime.now() + status_report_file = p.status_report_file if p.status_report_file != None else p.tspec_dir / "status_report.json" + status_report_file.parent.mkdir(parents=True, exist_ok=True) + pspec_path = p.pspec_path + reporting = initialize_reporting(status_report_file) - # s.goto(0) + try: + a = datetime.datetime.now() + pn = gettestModel() + print("[INFO] Loaded CPN model.") + # pn.n.draw('net-gv-graph.png') + s = StateGraph(pn.n) + # s.build() + # s.draw('test-gv-graph.png') + # print(" Finished Generation, writing to file.. ") + print("[INFO] Starting Reachability Graph Generation") + # pn.generateScenarios(s,0,[],[],[],0,300) + sys.setrecursionlimit(400) + pn.generateSCN() + print('Num Tests: ', pn.numTestCases) + print("[INFO] Finished.") + b = datetime.datetime.now() - fname = p.plantuml_dir / "rg.plantuml" - with open(fname, 'w') as f: - pn.generateReachabilityGraph(f) - print("[INFO] Created %s" % (fname,)) - c = datetime.datetime.now() - - print("[INFO] Starting Test Generation.") - pn.initializeTestGeneration() - pn.generateTestCases() - - # print('[INFO] Number-of-generated-scenario files: ',len(pn.visitedTList)) - print("[INFO] Test Generation Finished.") - d = datetime.datetime.now() + # s.goto(0) + + fname = p.plantuml_dir / "rg.plantuml" + with open(fname, 'w') as f: + pn.generateReachabilityGraph(f) + print("[INFO] Created %s" % (fname,)) + c = datetime.datetime.now() - print("[INFO] Creating Structure and Behavior Views in PlantUML.") - map_block_uml_txt = {} - for t in pn.n.transition(): - map_block_uml_txt[t.name.split('_')[0]] = '@startuml\n' + print("[INFO] Starting Test Generation.") + pn.initializeTestGeneration() + pn.generateTestCases() - for t in pn.n.transition(): - gtxt = map_block_uml_txt.get(t.name.split('_')[0]) - if 'json.loads' in t.guard._str: - # print(t.guard._str.replace('json.loads','')) - # print('\n'.join(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),55)))) - gtxt += 'component %s\n' % (t.name) - if len(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),68))) <= 2: - gtxt += 'note left of [%s]\n %s\nendnote\n' % (t.name, '\n'.join(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),55)))) - else: - gtxt += 'note bottom of [%s]\n %s\nendnote\n' % (t.name, '\n'.join(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),55)))) - else: - gtxt += 'component %s\n' % (t.name) - gtxt += 'note right of [%s]\n %s\nendnote\n' % (t.name, t.guard) - map_block_uml_txt[t.name.split('_')[0]] = gtxt + # print('[INFO] Number-of-generated-scenario files: ',len(pn.visitedTList)) + print("[INFO] Test Generation Finished.") + d = datetime.datetime.now() - for t in pn.n.transition(): - for inp in pn.n.pre(t.name): - txt = map_block_uml_txt.get(t.name.split('_')[0]) - if 'local' in inp: - txt += '%s -[#lightgrey]-> [%s]\n' % (inp, t.name) + print("[INFO] Creating Structure and Behavior Views in PlantUML.") + map_block_uml_txt = {} + for t in pn.n.transition(): + map_block_uml_txt[t.name.split('_')[0]] = '@startuml\n' + + for t in pn.n.transition(): + gtxt = map_block_uml_txt.get(t.name.split('_')[0]) + if 'json.loads' in t.guard._str: + # print(t.guard._str.replace('json.loads','')) + # print('\n'.join(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),55)))) + gtxt += 'component %s\n' % (t.name) + if len(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),68))) <= 2: + gtxt += 'note left of [%s]\n %s\nendnote\n' % (t.name, '\n'.join(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),55)))) + else: + gtxt += 'note bottom of [%s]\n %s\nendnote\n' % (t.name, '\n'.join(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),55)))) else: - txt += '%s --> [%s]\n' % (inp, t.name) - map_block_uml_txt[t.name.split('_')[0]] = txt - for out in pn.n.post(t.name): - txt = map_block_uml_txt.get(t.name.split('_')[0]) - if 'local' in out: - txt += '[%s] -[#lightgrey]-> %s\n' % (t.name, out) - else: - txt += '[%s] --> %s\n' % (t.name, out) - map_block_uml_txt[t.name.split('_')[0]] = txt - - for key in map_block_uml_txt: - txt = map_block_uml_txt.get(key) - txt += '@enduml\n' - map_block_uml_txt[key] = txt - fname = p.plantuml_dir / (key + ".plantuml") - with open(fname, 'w') as f: - f.write(txt) - - print("[INFO] View Generation Finished.") - e = datetime.datetime.now() - print("[INFO] Time Statistics") - print("[INFO] * Reachability Computation: %s" % (b - a)) - print("[INFO] * Reachability PUML Creation: %s" % (c - b)) - print("[INFO] * Test Generation: %s" % (d - c)) - print("[INFO] * PlantUML View Generation: %s" % (e - d)) - - # print("[INFO] Starting Command-Line Simulation.") - # simulate(pn.n) - - #if not p.no_sim: - # print('[SIM] Start Simulation? (Y/N) :') - # value = input(" Enter Choice: ") - # if value == "Y" or value == "y": - # os.system('cls') - # simulate(pn.n) - - print("[INFO] Exiting..") + gtxt += 'component %s\n' % (t.name) + gtxt += 'note right of [%s]\n %s\nendnote\n' % (t.name, t.guard) + map_block_uml_txt[t.name.split('_')[0]] = gtxt + + for t in pn.n.transition(): + for inp in pn.n.pre(t.name): + txt = map_block_uml_txt.get(t.name.split('_')[0]) + if 'local' in inp: + txt += '%s -[#lightgrey]-> [%s]\n' % (inp, t.name) + else: + txt += '%s --> [%s]\n' % (inp, t.name) + map_block_uml_txt[t.name.split('_')[0]] = txt + for out in pn.n.post(t.name): + txt = map_block_uml_txt.get(t.name.split('_')[0]) + if 'local' in out: + txt += '[%s] -[#lightgrey]-> %s\n' % (t.name, out) + else: + txt += '[%s] --> %s\n' % (t.name, out) + map_block_uml_txt[t.name.split('_')[0]] = txt + + for key in map_block_uml_txt: + txt = map_block_uml_txt.get(key) + txt += '@enduml\n' + map_block_uml_txt[key] = txt + fname = p.plantuml_dir / (key + ".plantuml") + with open(fname, 'w') as f: + f.write(txt) + + print("[INFO] View Generation Finished.") + e = datetime.datetime.now() + print("[INFO] Time Statistics") + print("[INFO] * Reachability Computation: %s" % (b - a)) + print("[INFO] * Reachability PUML Creation: %s" % (c - b)) + print("[INFO] * Test Generation: %s" % (d - c)) + print("[INFO] * PlantUML View Generation: %s" % (e - d)) + + # print("[INFO] Starting Command-Line Simulation.") + # simulate(pn.n) + + #if not p.no_sim: + # print('[SIM] Start Simulation? (Y/N) :') + # value = input(" Enter Choice: ") + # if value == "Y" or value == "y": + # os.system('cls') + # simulate(pn.n) + + except Exception as e: + print("[ERROR] " + str(e)) + if not isinstance(e, StatusException): + get_reporting().exception(message = e.__class__.__name__, exception = e) + finally: + print("[INFO] Saving status_report.json") + severity = reporting.save() + print("[INFO] Saved status_report.json") + print(f"[INFO] Exiting with status: {severity.name}") + exit(severity.value) diff --git a/bundles/nl.asml.matala.product.tests/resources/expected/gettest/CPNServer/gettest/gettest_TestSCN.py b/bundles/nl.asml.matala.product.tests/resources/expected/gettest/CPNServer/gettest/gettest_TestSCN.py index a13222e9..61e9937a 100644 --- a/bundles/nl.asml.matala.product.tests/resources/expected/gettest/CPNServer/gettest/gettest_TestSCN.py +++ b/bundles/nl.asml.matala.product.tests/resources/expected/gettest/CPNServer/gettest/gettest_TestSCN.py @@ -22,12 +22,13 @@ class TestSCN: constraint_dict = {} tr_assert_ref_dict = {} - def __init__(self, _mapTrAssert, _constraint_dict, _tr_assert_ref_dict): + def __init__(self, _pspec_path, _mapTrAssert, _constraint_dict, _tr_assert_ref_dict): self.step_list = [] self.step_dependencies = [] self.map_transition_assert = _mapTrAssert self.constraint_dict = _constraint_dict self.tr_assert_ref_dict = _tr_assert_ref_dict + self.pspec_path = _pspec_path def generate_viz(self, idx, output_dir): txt = "@startuml\n" @@ -73,7 +74,7 @@ def recurseJson(self, items, prefix): raise TypeError('Unsupported type') txt += f" {prefix} := {items}\n" return txt - + def printData(self, idata): txt = "" for k, v in idata.items(): @@ -83,10 +84,10 @@ def printData(self, idata): # for jk in j.keys(): # txt += self.recurseJson(j[jk], "%s.%s" % (k,jk)) return txt - + def generateTSpec(self, idx, sutTypesList, sutVarTransitionMap, transitionQnameMap, output_dir): txt = "" - txt += "import \"gettest.ps\"\n\n" + txt += f"""import "{self.pspec_path}gettest.ps"\n\n""" txt += "using gettest.Root.test\n" txt += "using gettest.Root.single\n" txt += "\nabstract-test-definition\n\n" @@ -297,8 +298,8 @@ class CEntry: name = "" constr = "" + def __init__(self, n, c): self.name = n self.constr = c - diff --git a/bundles/nl.asml.matala.product.tests/resources/expected/gettest/CPNServer/gettest/gettest_data.py b/bundles/nl.asml.matala.product.tests/resources/expected/gettest/CPNServer/gettest/gettest_data.py index 44170b8b..675bf1a4 100644 --- a/bundles/nl.asml.matala.product.tests/resources/expected/gettest/CPNServer/gettest/gettest_data.py +++ b/bundles/nl.asml.matala.product.tests/resources/expected/gettest/CPNServer/gettest/gettest_data.py @@ -1,6 +1,9 @@ import copy import json - +if __package__ is None or __package__ == '': + from gettest_reporting import get_reporting, Location +else: + from .gettest_reporting import get_reporting, Location class Data: @@ -29,6 +32,11 @@ def get_Single(): @staticmethod def execute_Root_T1_default_single(test): - single = {"aString": list(test["aMap"].items())[2][1], "aInt": test["aList"][2]} + try: + single = {"aString": list(test["aMap"].items())[2][1], "aInt": test["aList"][2]} + except Exception as e: + __location = Location(28,31,523,107,"single := Single { aString = get(test.aMap, 2), aInt = get(test.aList, 2) }") + __source_file = "gettest.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(single) diff --git a/bundles/nl.asml.matala.product.tests/resources/expected/gettest/CPNServer/gettest/gettest_reporting.py b/bundles/nl.asml.matala.product.tests/resources/expected/gettest/CPNServer/gettest/gettest_reporting.py new file mode 100644 index 00000000..5d65d98e --- /dev/null +++ b/bundles/nl.asml.matala.product.tests/resources/expected/gettest/CPNServer/gettest/gettest_reporting.py @@ -0,0 +1,153 @@ +import json +import traceback +from enum import Enum +from typing import List, Optional, Dict, Any +from dataclasses import dataclass, field +from pathlib import Path + +class StatusException(Exception): + def __init__(self, message: str): + super().__init__(message) + +class Severity(Enum): + OK = 0 + INFO = 1 + WARNING = 2 + ERROR = 3 + CANCEL = 4 + +@dataclass +class Location: + startLine: int + endLine: int + offset: int + length: int + text: str + + def to_dict(self) -> Dict[str, Any]: + return { + 'startLine': self.startLine, + 'endLine': self.endLine, + 'offset': self.offset, + 'length': self.length, + 'text': self.text, + } + +@dataclass +class StatusReport: + plugin: str + severity: Severity + message: str + source: str = "" + code: int = 0 + details: Optional[str] = None + location: Optional[Location] = None + children: List['StatusReport'] = field(default_factory=list) + exception: Optional[Exception] = field(default=None, repr=False) + + def __post_init__(self): + if self.exception is not None: + if self.details is None: + self.details = self._get_stack_trace_as_string(self.exception) + self.exception = None # Don't retain non-serializable object + + if self.children: + child_severities = [child.severity for child in self.children if child is not None] + if child_severities: + max_child_severity = max(child_severities, key=lambda s: s.value) + if max_child_severity.value > self.severity.value: + self.severity = max_child_severity + + @staticmethod + def _get_stack_trace_as_string(exception: Exception) -> str: + if exception is None: + return None + tb_lines = traceback.format_exception(type(exception), exception, exception.__traceback__) + if len(tb_lines) > 15: + tb_lines = tb_lines[:15] + [f"\t... {len(tb_lines) - 15} more\n"] + return "".join(tb_lines) + + def to_dict(self) -> Dict[str, Any]: + return { + 'plugin': self.plugin, + 'severity': self.severity.name, + 'message': self.message, + 'source': self.source, + 'code': self.code, + 'details': self.details, + 'location': self.location.to_dict() if self.location else None, + 'children': [child.to_dict() for child in self.children if child is not None], + } + +class StatusReporting: + def __init__(self, save_path: str): + self.save_path = Path(save_path) + self.reports: List[StatusReport] = [] + + def _log(self, severity: Severity, message: str, source: str = "", code: int = 0, + details: Optional[str] = None, exception: Optional[Exception] = None, location: Optional[Location] = None) -> StatusReport: + report = StatusReport( + plugin="", + severity=severity, + message=message, + source=source, + code=code, + details=details, + location=location, + exception=exception + ) + self.reports.append(report) + return report + + def info(self, message: str, source: str = "", code: int = 0, details: Optional[str] = None, location: Location = None) -> StatusReport: + return self._log(Severity.INFO, message, source, code, details, None, location) + + def warning(self, message: str, source: str = "", code: int = 0, details: Optional[str] = None, location: Location = None) -> StatusReport: + return self._log(Severity.WARNING, message, source, code, details, None, location) + + def error(self, message: str, source: str = "", code: int = 0, + details: Optional[str] = None, location: Location = None) -> StatusReport: + return self._log(Severity.ERROR, message, source, code, details, None, location) + + def exception(self, message: str, exception: Exception, source: str = "", details: str = None, code: int = 0, location: Location = None) -> StatusReport: + self._log(Severity.ERROR, message, source, code, details, exception, location) + #on exception the process is stopped + raise StatusException(message) + + def save(self) -> Severity: + + root_severity = Severity.OK + if self.reports: + root_severity = max((report.severity for report in self.reports), key=lambda s: s.value) + + root_report = StatusReport( + plugin="", + severity=root_severity, + message=f"Python generation of gettest", + source="", + code=0, + details=None, + location=None, + children=self.reports, + exception=None + ) + + data = root_report.to_dict() + with open(self.save_path, 'w') as f: + json.dump(data, f, indent=2) + + return root_severity + + +_status_reporting_instance: Optional[StatusReporting] = None + +def initialize_reporting(save_path: str) -> StatusReporting: + global _status_reporting_instance + _status_reporting_instance = StatusReporting(save_path) + return _status_reporting_instance + +def get_reporting() -> StatusReporting: + global _status_reporting_instance + if _status_reporting_instance is None: + raise RuntimeError("StatusReporting not initialized. Call initialize_reporting() first.") + return _status_reporting_instance diff --git a/bundles/nl.asml.matala.product.tests/resources/expected/imaging/CPNServer/imaging/imaging.py b/bundles/nl.asml.matala.product.tests/resources/expected/imaging/CPNServer/imaging/imaging.py index 0a6fb785..0a32f5f2 100644 --- a/bundles/nl.asml.matala.product.tests/resources/expected/imaging/CPNServer/imaging/imaging.py +++ b/bundles/nl.asml.matala.product.tests/resources/expected/imaging/CPNServer/imaging/imaging.py @@ -10,10 +10,12 @@ if __package__ is None or __package__ == '': from imaging_TestSCN import TestSCN, Step, Tests, Constraint, CEntry from imaging_data import Data + from imaging_reporting import get_reporting, initialize_reporting, Location from imaging_Simulation import Simulation, simulate else: from .imaging_TestSCN import TestSCN, Step, Tests, Constraint, CEntry from .imaging_data import Data + from .imaging_reporting import get_reporting, initialize_reporting, Location from .imaging_Simulation import Simulation, simulate import subprocess import copy @@ -520,7 +522,8 @@ def initializeTestGeneration(self): if k + "_" +elm.__repr__() in self.map_transition_modes_to_name: print("WARN: duplicate modes detected for same transition.") print(k + "_" +elm.__repr__()) - print("WARN: references to the above transitions are ambigous!") + print("WARN: references to the above transitions are ambiguous!") + get_reporting().warning("Duplicate modes detected for same transition, Check References in Details", details=f"{k}_{str.join('\n',[str(s) for s in elm.items()])}") self.map_transition_modes_to_name[k + "_" +elm.__repr__()] = k + "_" + str(cnt) # self.map_transition_modes_to_name[k + "_" + pprint.pformat(elm.items(), width=60, compact=True,depth=5)] = k + "_" + str(cnt) cnt = cnt + 1 @@ -542,7 +545,7 @@ def generateTestCases(self): for entry in pn.visitedTList: # txt = '' if entry: - _test_scn = TestSCN(self.map_transition_assert, self.constraint_dict, self.tr_assert_ref_dict) + _test_scn = TestSCN(pspec_path, self.map_transition_assert, self.constraint_dict, self.tr_assert_ref_dict) idx = idx + 1 j = 0 for step in entry: @@ -630,103 +633,127 @@ def copy(self, name=None): type=bool, default=False, help="Disable simulation") - + + parser.add_argument("-srfile","--status_report_file", + type=Path, + default=None, + help="The path to where the status report will be saved") + + parser.add_argument("-pspath","--pspec_path", + type=str, + default="", + help="The relatve path to the pspec file to be used for test generation") + p = parser.parse_args() p.tspec_dir.mkdir(exist_ok=True) p.plantuml_dir.mkdir(exist_ok=True) - - a = datetime.datetime.now() - pn = imagingModel() - print("[INFO] Loaded CPN model.") - # pn.n.draw('net-gv-graph.png') - s = StateGraph(pn.n) - # s.build() - # s.draw('test-gv-graph.png') - # print(" Finished Generation, writing to file.. ") - print("[INFO] Starting Reachability Graph Generation") - # pn.generateScenarios(s,0,[],[],[],0,300) - sys.setrecursionlimit(400) - pn.generateSCN() - print('Num Tests: ', pn.numTestCases) - print("[INFO] Finished.") - b = datetime.datetime.now() + status_report_file = p.status_report_file if p.status_report_file != None else p.tspec_dir / "status_report.json" + status_report_file.parent.mkdir(parents=True, exist_ok=True) + pspec_path = p.pspec_path + reporting = initialize_reporting(status_report_file) - # s.goto(0) + try: + a = datetime.datetime.now() + pn = imagingModel() + print("[INFO] Loaded CPN model.") + # pn.n.draw('net-gv-graph.png') + s = StateGraph(pn.n) + # s.build() + # s.draw('test-gv-graph.png') + # print(" Finished Generation, writing to file.. ") + print("[INFO] Starting Reachability Graph Generation") + # pn.generateScenarios(s,0,[],[],[],0,300) + sys.setrecursionlimit(400) + pn.generateSCN() + print('Num Tests: ', pn.numTestCases) + print("[INFO] Finished.") + b = datetime.datetime.now() - fname = p.plantuml_dir / "rg.plantuml" - with open(fname, 'w') as f: - pn.generateReachabilityGraph(f) - print("[INFO] Created %s" % (fname,)) - c = datetime.datetime.now() - - print("[INFO] Starting Test Generation.") - pn.initializeTestGeneration() - pn.generateTestCases() - - # print('[INFO] Number-of-generated-scenario files: ',len(pn.visitedTList)) - print("[INFO] Test Generation Finished.") - d = datetime.datetime.now() + # s.goto(0) + + fname = p.plantuml_dir / "rg.plantuml" + with open(fname, 'w') as f: + pn.generateReachabilityGraph(f) + print("[INFO] Created %s" % (fname,)) + c = datetime.datetime.now() - print("[INFO] Creating Structure and Behavior Views in PlantUML.") - map_block_uml_txt = {} - for t in pn.n.transition(): - map_block_uml_txt[t.name.split('_')[0]] = '@startuml\n' + print("[INFO] Starting Test Generation.") + pn.initializeTestGeneration() + pn.generateTestCases() - for t in pn.n.transition(): - gtxt = map_block_uml_txt.get(t.name.split('_')[0]) - if 'json.loads' in t.guard._str: - # print(t.guard._str.replace('json.loads','')) - # print('\n'.join(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),55)))) - gtxt += 'component %s\n' % (t.name) - if len(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),68))) <= 2: - gtxt += 'note left of [%s]\n %s\nendnote\n' % (t.name, '\n'.join(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),55)))) - else: - gtxt += 'note bottom of [%s]\n %s\nendnote\n' % (t.name, '\n'.join(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),55)))) - else: - gtxt += 'component %s\n' % (t.name) - gtxt += 'note right of [%s]\n %s\nendnote\n' % (t.name, t.guard) - map_block_uml_txt[t.name.split('_')[0]] = gtxt + # print('[INFO] Number-of-generated-scenario files: ',len(pn.visitedTList)) + print("[INFO] Test Generation Finished.") + d = datetime.datetime.now() - for t in pn.n.transition(): - for inp in pn.n.pre(t.name): - txt = map_block_uml_txt.get(t.name.split('_')[0]) - if 'local' in inp: - txt += '%s -[#lightgrey]-> [%s]\n' % (inp, t.name) + print("[INFO] Creating Structure and Behavior Views in PlantUML.") + map_block_uml_txt = {} + for t in pn.n.transition(): + map_block_uml_txt[t.name.split('_')[0]] = '@startuml\n' + + for t in pn.n.transition(): + gtxt = map_block_uml_txt.get(t.name.split('_')[0]) + if 'json.loads' in t.guard._str: + # print(t.guard._str.replace('json.loads','')) + # print('\n'.join(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),55)))) + gtxt += 'component %s\n' % (t.name) + if len(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),68))) <= 2: + gtxt += 'note left of [%s]\n %s\nendnote\n' % (t.name, '\n'.join(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),55)))) + else: + gtxt += 'note bottom of [%s]\n %s\nendnote\n' % (t.name, '\n'.join(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),55)))) else: - txt += '%s --> [%s]\n' % (inp, t.name) - map_block_uml_txt[t.name.split('_')[0]] = txt - for out in pn.n.post(t.name): - txt = map_block_uml_txt.get(t.name.split('_')[0]) - if 'local' in out: - txt += '[%s] -[#lightgrey]-> %s\n' % (t.name, out) - else: - txt += '[%s] --> %s\n' % (t.name, out) - map_block_uml_txt[t.name.split('_')[0]] = txt - - for key in map_block_uml_txt: - txt = map_block_uml_txt.get(key) - txt += '@enduml\n' - map_block_uml_txt[key] = txt - fname = p.plantuml_dir / (key + ".plantuml") - with open(fname, 'w') as f: - f.write(txt) - - print("[INFO] View Generation Finished.") - e = datetime.datetime.now() - print("[INFO] Time Statistics") - print("[INFO] * Reachability Computation: %s" % (b - a)) - print("[INFO] * Reachability PUML Creation: %s" % (c - b)) - print("[INFO] * Test Generation: %s" % (d - c)) - print("[INFO] * PlantUML View Generation: %s" % (e - d)) - - # print("[INFO] Starting Command-Line Simulation.") - # simulate(pn.n) - - #if not p.no_sim: - # print('[SIM] Start Simulation? (Y/N) :') - # value = input(" Enter Choice: ") - # if value == "Y" or value == "y": - # os.system('cls') - # simulate(pn.n) - - print("[INFO] Exiting..") + gtxt += 'component %s\n' % (t.name) + gtxt += 'note right of [%s]\n %s\nendnote\n' % (t.name, t.guard) + map_block_uml_txt[t.name.split('_')[0]] = gtxt + + for t in pn.n.transition(): + for inp in pn.n.pre(t.name): + txt = map_block_uml_txt.get(t.name.split('_')[0]) + if 'local' in inp: + txt += '%s -[#lightgrey]-> [%s]\n' % (inp, t.name) + else: + txt += '%s --> [%s]\n' % (inp, t.name) + map_block_uml_txt[t.name.split('_')[0]] = txt + for out in pn.n.post(t.name): + txt = map_block_uml_txt.get(t.name.split('_')[0]) + if 'local' in out: + txt += '[%s] -[#lightgrey]-> %s\n' % (t.name, out) + else: + txt += '[%s] --> %s\n' % (t.name, out) + map_block_uml_txt[t.name.split('_')[0]] = txt + + for key in map_block_uml_txt: + txt = map_block_uml_txt.get(key) + txt += '@enduml\n' + map_block_uml_txt[key] = txt + fname = p.plantuml_dir / (key + ".plantuml") + with open(fname, 'w') as f: + f.write(txt) + + print("[INFO] View Generation Finished.") + e = datetime.datetime.now() + print("[INFO] Time Statistics") + print("[INFO] * Reachability Computation: %s" % (b - a)) + print("[INFO] * Reachability PUML Creation: %s" % (c - b)) + print("[INFO] * Test Generation: %s" % (d - c)) + print("[INFO] * PlantUML View Generation: %s" % (e - d)) + + # print("[INFO] Starting Command-Line Simulation.") + # simulate(pn.n) + + #if not p.no_sim: + # print('[SIM] Start Simulation? (Y/N) :') + # value = input(" Enter Choice: ") + # if value == "Y" or value == "y": + # os.system('cls') + # simulate(pn.n) + + except Exception as e: + print("[ERROR] " + str(e)) + if not isinstance(e, StatusException): + get_reporting().exception(message = e.__class__.__name__, exception = e) + finally: + print("[INFO] Saving status_report.json") + severity = reporting.save() + print("[INFO] Saved status_report.json") + print(f"[INFO] Exiting with status: {severity.name}") + exit(severity.value) diff --git a/bundles/nl.asml.matala.product.tests/resources/expected/imaging/CPNServer/imaging/imaging_TestSCN.py b/bundles/nl.asml.matala.product.tests/resources/expected/imaging/CPNServer/imaging/imaging_TestSCN.py index 03f33dae..a580c1ea 100644 --- a/bundles/nl.asml.matala.product.tests/resources/expected/imaging/CPNServer/imaging/imaging_TestSCN.py +++ b/bundles/nl.asml.matala.product.tests/resources/expected/imaging/CPNServer/imaging/imaging_TestSCN.py @@ -22,12 +22,13 @@ class TestSCN: constraint_dict = {} tr_assert_ref_dict = {} - def __init__(self, _mapTrAssert, _constraint_dict, _tr_assert_ref_dict): + def __init__(self, _pspec_path, _mapTrAssert, _constraint_dict, _tr_assert_ref_dict): self.step_list = [] self.step_dependencies = [] self.map_transition_assert = _mapTrAssert self.constraint_dict = _constraint_dict self.tr_assert_ref_dict = _tr_assert_ref_dict + self.pspec_path = _pspec_path def generate_viz(self, idx, output_dir): txt = "@startuml\n" @@ -73,7 +74,7 @@ def recurseJson(self, items, prefix): raise TypeError('Unsupported type') txt += f" {prefix} := {items}\n" return txt - + def printData(self, idata): txt = "" for k, v in idata.items(): @@ -83,10 +84,10 @@ def printData(self, idata): # for jk in j.keys(): # txt += self.recurseJson(j[jk], "%s.%s" % (k,jk)) return txt - + def generateTSpec(self, idx, sutTypesList, sutVarTransitionMap, transitionQnameMap, output_dir): txt = "" - txt += "import \"imaging.ps\"\n\n" + txt += f"""import "{self.pspec_path}imaging.ps"\n\n""" txt += "using imaging.SupervisonModelSupervisionImagePreparation.ImagingRequest\n" txt += "using imaging.SupervisonModelSupervisionImagePreparation.AcqUpdate\n" txt += "using imaging.SupervisonModelSupervisionImagePreparation.EqStatus\n" @@ -351,8 +352,8 @@ class CEntry: name = "" constr = "" + def __init__(self, n, c): self.name = n self.constr = c - diff --git a/bundles/nl.asml.matala.product.tests/resources/expected/imaging/CPNServer/imaging/imaging_data.py b/bundles/nl.asml.matala.product.tests/resources/expected/imaging/CPNServer/imaging/imaging_data.py index e882739d..2c6c1410 100644 --- a/bundles/nl.asml.matala.product.tests/resources/expected/imaging/CPNServer/imaging/imaging_data.py +++ b/bundles/nl.asml.matala.product.tests/resources/expected/imaging/CPNServer/imaging/imaging_data.py @@ -1,6 +1,9 @@ import copy import json - +if __package__ is None or __package__ == '': + from imaging_reporting import get_reporting, Location +else: + from .imaging_reporting import get_reporting, Location class Data: @@ -97,416 +100,871 @@ def get_VacuumEnum(): @staticmethod def execute_SupervisonModelSupervisionImagePreparation_Unprepare_default_AcquisitionReq(ImagingRequest): - AcquisitionReq = {"cmd_type": ImagingRequest["cmd_type"], "id": ImagingRequest["id"]} + try: + AcquisitionReq = {"cmd_type": ImagingRequest["cmd_type"], "id": ImagingRequest["id"]} + except Exception as e: + __location = Location(41,44,1101,128,"AcquisitionReq := AcqReq { cmd_type = ImagingRequest.cmd_type, id = ImagingRequest.id }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(AcquisitionReq) @staticmethod def execute_SupervisonModelSupervisionImagePreparation_Prepare_default_AcquisitionReq(ImagingRequest,EqStatus): - AcquisitionReq = {"cmd_type": ImagingRequest["cmd_type"], "id": ImagingRequest["id"]} + try: + AcquisitionReq = {"cmd_type": ImagingRequest["cmd_type"], "id": ImagingRequest["id"]} + except Exception as e: + __location = Location(54,57,1647,128,"AcquisitionReq := AcqReq { cmd_type = ImagingRequest.cmd_type, id = ImagingRequest.id }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(AcquisitionReq) @staticmethod def execute_SupervisonModelSupervisionImagePreparation_Prepare_default_EqStatus(ImagingRequest,EqStatus): - EqStatus = EqStatus + try: + EqStatus = EqStatus + except Exception as e: + __location = Location(60,60,1865,20,"EqStatus := EqStatus") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(EqStatus) @staticmethod def execute_SupervisonModelSupervisionImagePreparation_Waitforprepare_default_Gateway_102q82v(Flow_0kkvgdv,AcqUpdate,EqStatus): - Gateway_102q82v = Flow_0kkvgdv + try: + Gateway_102q82v = Flow_0kkvgdv + except Exception as e: + __location = Location(68,68,2133,31,"Gateway_102q82v := Flow_0kkvgdv") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Gateway_102q82v) @staticmethod def execute_SupervisonModelSupervisionImagePreparation_Waitforprepare_default_EqStatus(Flow_0kkvgdv,AcqUpdate,EqStatus): - EqStatus = {"temp_status": EqStatus["temp_status"], "pump_status": EqStatus["pump_status"], "acq_status": "Status::PREPARING"} + try: + EqStatus = {"temp_status": EqStatus["temp_status"], "pump_status": EqStatus["pump_status"], "acq_status": "Status::PREPARING"} + except Exception as e: + __location = Location(72,76,2271,187,"EqStatus:=EquipmentStatus { temp_status = EqStatus.temp_status, pump_status = EqStatus.pump_status, acq_status = Status::PREPARING }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(EqStatus) @staticmethod def execute_SupervisonModelSupervisionImagePreparation_WaitforUnprepare_default_Gateway_102q82v(AcqUpdate,EqStatus,Flow_1kpcqqf): - Gateway_102q82v = Flow_1kpcqqf + try: + Gateway_102q82v = Flow_1kpcqqf + except Exception as e: + __location = Location(84,84,2710,31,"Gateway_102q82v := Flow_1kpcqqf") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Gateway_102q82v) @staticmethod def execute_SupervisonModelSupervisionImagePreparation_WaitforUnprepare_default_EqStatus(AcqUpdate,EqStatus,Flow_1kpcqqf): - EqStatus = {"temp_status": EqStatus["temp_status"], "pump_status": EqStatus["pump_status"], "acq_status": "Status::UNPREPARING"} + try: + EqStatus = {"temp_status": EqStatus["temp_status"], "pump_status": EqStatus["pump_status"], "acq_status": "Status::UNPREPARING"} + except Exception as e: + __location = Location(88,92,2848,189,"EqStatus:=EquipmentStatus { temp_status = EqStatus.temp_status, pump_status = EqStatus.pump_status, acq_status = Status::UNPREPARING }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(EqStatus) @staticmethod def execute_SupervisonModelPumpController_done_default_Gateway_0td58pc(Flow_0x0gs9b): - Gateway_0td58pc = Flow_0x0gs9b + try: + Gateway_0td58pc = Flow_0x0gs9b + except Exception as e: + __location = Location(123,123,3693,31,"Gateway_0td58pc := Flow_0x0gs9b") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Gateway_0td58pc) @staticmethod def execute_SupervisonModelPumpController_done_default_PumpUpdate(Flow_0x0gs9b): - PumpUpdate = {"result": "ResponseEnum::OK"} + try: + PumpUpdate = {"result": "ResponseEnum::OK"} + except Exception as e: + __location = Location(126,126,3793,52,"PumpUpdate := PumpResp { result = ResponseEnum::OK }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(PumpUpdate) @staticmethod def execute_SupervisonModelPumpController_startpump_default_Flow_0x0gs9b(PumpRequest): - Flow_0x0gs9b = {"id": PumpRequest["id"]} + try: + Flow_0x0gs9b = {"id": PumpRequest["id"]} + except Exception as e: + __location = Location(135,135,4152,43,"Flow_0x0gs9b := CTX { id = PumpRequest.id }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Flow_0x0gs9b) @staticmethod def execute_SupervisonModelPumpController_stoppump_default_Flow_104f6k4(PumpRequest): - Flow_104f6k4 = {"id": PumpRequest["id"]} + try: + Flow_104f6k4 = {"id": PumpRequest["id"]} + except Exception as e: + __location = Location(144,144,4501,43,"Flow_104f6k4 := CTX { id = PumpRequest.id }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Flow_104f6k4) @staticmethod def execute_SupervisonModelPumpController_pumpstopped_default_Gateway_0td58pc(Flow_104f6k4): - Gateway_0td58pc = Flow_104f6k4 + try: + Gateway_0td58pc = Flow_104f6k4 + except Exception as e: + __location = Location(152,152,4755,31,"Gateway_0td58pc := Flow_104f6k4") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Gateway_0td58pc) @staticmethod def execute_SupervisonModelPumpController_pumpstopped_default_PumpUpdate(Flow_104f6k4): - PumpUpdate = {"result": "ResponseEnum::OK"} + try: + PumpUpdate = {"result": "ResponseEnum::OK"} + except Exception as e: + __location = Location(155,155,4855,52,"PumpUpdate := PumpResp { result = ResponseEnum::OK }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(PumpUpdate) @staticmethod def execute_SupervisonModelImagingController_WaitforUnprepareImaging_default_Gateway_0gu94f4(Flow_05szwsj,ImagingUpdate): - Gateway_0gu94f4 = Flow_05szwsj + try: + Gateway_0gu94f4 = Flow_05szwsj + except Exception as e: + __location = Location(193,193,5820,31,"Gateway_0gu94f4 := Flow_05szwsj") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Gateway_0gu94f4) @staticmethod def execute_SupervisonModelImagingController_returntoprep_default_Gateway_0xpxevh(Gateway_0gu94f4): - Gateway_0xpxevh = Gateway_0gu94f4 + try: + Gateway_0xpxevh = Gateway_0gu94f4 + except Exception as e: + __location = Location(201,201,6068,34,"Gateway_0xpxevh := Gateway_0gu94f4") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Gateway_0xpxevh) @staticmethod def execute_SupervisonModelImagingController_UnprepareImaging_default_Flow_05szwsj(Gateway_0i3nw09): - Flow_05szwsj = Gateway_0i3nw09 - Flow_05szwsj["id"] = Flow_05szwsj["id"] + 1 + try: + Flow_05szwsj = Gateway_0i3nw09 + except Exception as e: + __location = Location(209,209,6323,31,"Flow_05szwsj := Gateway_0i3nw09") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) + try: + Flow_05szwsj["id"] = Flow_05szwsj["id"] + 1 + except Exception as e: + __location = Location(210,210,6368,36,"Flow_05szwsj.id := Flow_05szwsj.id+1") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Flow_05szwsj) @staticmethod def execute_SupervisonModelImagingController_UnprepareImaging_default_ImagingRequest(Gateway_0i3nw09): - ImagingRequest = {"cmd_type": "ImageEnum::UNPREPARE", "id": Gateway_0i3nw09["id"], "image_quality": "ImageQuality::NA"} + try: + ImagingRequest = {"cmd_type": "ImageEnum::UNPREPARE", "id": Gateway_0i3nw09["id"], "image_quality": "ImageQuality::NA"} + except Exception as e: + __location = Location(213,213,6477,118,"ImagingRequest:= ImgReq { cmd_type = ImageEnum::UNPREPARE, id = Gateway_0i3nw09.id, image_quality = ImageQuality::NA }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(ImagingRequest) @staticmethod def execute_SupervisonModelImagingController_WaitforImagingStopped_default_Gateway_0i3nw09(Flow_0ncxpgd,ImagingUpdate): - Gateway_0i3nw09 = Flow_0ncxpgd + try: + Gateway_0i3nw09 = Flow_0ncxpgd + except Exception as e: + __location = Location(221,221,6843,31,"Gateway_0i3nw09 := Flow_0ncxpgd") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Gateway_0i3nw09) @staticmethod def execute_SupervisonModelImagingController_StartLowResImaging_default_Gateway_08l0os0(Gateway_0kvhy0o): - Gateway_08l0os0 = Gateway_0kvhy0o - Gateway_08l0os0["id"] = Gateway_08l0os0["id"] + 1 + try: + Gateway_08l0os0 = Gateway_0kvhy0o + except Exception as e: + __location = Location(229,229,7104,34,"Gateway_08l0os0 := Gateway_0kvhy0o") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) + try: + Gateway_08l0os0["id"] = Gateway_08l0os0["id"] + 1 + except Exception as e: + __location = Location(230,230,7152,42,"Gateway_08l0os0.id := Gateway_08l0os0.id+1") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Gateway_08l0os0) @staticmethod def execute_SupervisonModelImagingController_StartLowResImaging_default_ImagingRequest(Gateway_0kvhy0o): - ImagingRequest = {"cmd_type": "ImageEnum::START", "id": Gateway_0kvhy0o["id"], "image_quality": "ImageQuality::LOW"} + try: + ImagingRequest = {"cmd_type": "ImageEnum::START", "id": Gateway_0kvhy0o["id"], "image_quality": "ImageQuality::LOW"} + except Exception as e: + __location = Location(233,233,7267,116,"ImagingRequest := ImgReq { cmd_type = ImageEnum::START, id = Gateway_0kvhy0o.id, image_quality = ImageQuality::LOW }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(ImagingRequest) @staticmethod def execute_SupervisonModelImagingController_nextimage_default_Gateway_0kvhy0o(Gateway_0i3nw09): - Gateway_0kvhy0o = Gateway_0i3nw09 + try: + Gateway_0kvhy0o = Gateway_0i3nw09 + except Exception as e: + __location = Location(241,241,7593,34,"Gateway_0kvhy0o := Gateway_0i3nw09") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Gateway_0kvhy0o) @staticmethod def execute_SupervisonModelImagingController_StartHighResImaging_default_Gateway_08l0os0(Gateway_0kvhy0o): - Gateway_08l0os0 = Gateway_0kvhy0o - Gateway_08l0os0["id"] = Gateway_08l0os0["id"] + 1 + try: + Gateway_08l0os0 = Gateway_0kvhy0o + except Exception as e: + __location = Location(249,249,7859,34,"Gateway_08l0os0 := Gateway_0kvhy0o") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) + try: + Gateway_08l0os0["id"] = Gateway_08l0os0["id"] + 1 + except Exception as e: + __location = Location(250,250,7907,42,"Gateway_08l0os0.id := Gateway_08l0os0.id+1") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Gateway_08l0os0) @staticmethod def execute_SupervisonModelImagingController_StartHighResImaging_default_ImagingRequest(Gateway_0kvhy0o): - ImagingRequest = {"cmd_type": "ImageEnum::START", "id": Gateway_0kvhy0o["id"], "image_quality": "ImageQuality::HIGH"} + try: + ImagingRequest = {"cmd_type": "ImageEnum::START", "id": Gateway_0kvhy0o["id"], "image_quality": "ImageQuality::HIGH"} + except Exception as e: + __location = Location(253,253,8022,117,"ImagingRequest := ImgReq { cmd_type = ImageEnum::START, id = Gateway_0kvhy0o.id, image_quality = ImageQuality::HIGH }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(ImagingRequest) @staticmethod def execute_SupervisonModelImagingController_Stopimaging_default_Flow_0ncxpgd(Flow_1k04xzh): - Flow_0ncxpgd = Flow_1k04xzh - Flow_0ncxpgd["id"] = Flow_0ncxpgd["id"] + 1 + try: + Flow_0ncxpgd = Flow_1k04xzh + except Exception as e: + __location = Location(261,261,8347,28,"Flow_0ncxpgd := Flow_1k04xzh") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) + try: + Flow_0ncxpgd["id"] = Flow_0ncxpgd["id"] + 1 + except Exception as e: + __location = Location(262,262,8389,36,"Flow_0ncxpgd.id := Flow_0ncxpgd.id+1") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Flow_0ncxpgd) @staticmethod def execute_SupervisonModelImagingController_Stopimaging_default_ImagingRequest(Flow_1k04xzh): - ImagingRequest = {"cmd_type": "ImageEnum::STOP", "id": Flow_1k04xzh["id"], "image_quality": "ImageQuality::NA"} + try: + ImagingRequest = {"cmd_type": "ImageEnum::STOP", "id": Flow_1k04xzh["id"], "image_quality": "ImageQuality::NA"} + except Exception as e: + __location = Location(265,265,8498,111,"ImagingRequest := ImgReq { cmd_type = ImageEnum::STOP, id = Flow_1k04xzh.id, image_quality = ImageQuality::NA }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(ImagingRequest) @staticmethod def execute_SupervisonModelImagingController_WaitforPrepared_default_Gateway_0kvhy0o(Flow_029nrs5,ImagingUpdate): - Gateway_0kvhy0o = Flow_029nrs5 + try: + Gateway_0kvhy0o = Flow_029nrs5 + except Exception as e: + __location = Location(273,273,8844,31,"Gateway_0kvhy0o := Flow_029nrs5") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Gateway_0kvhy0o) @staticmethod def execute_SupervisonModelImagingController_PrepareImaging_default_Flow_029nrs5(Gateway_0xpxevh): - Flow_029nrs5 = Gateway_0xpxevh - Flow_029nrs5["id"] = Flow_029nrs5["id"] + 1 + try: + Flow_029nrs5 = Gateway_0xpxevh + except Exception as e: + __location = Location(281,281,9092,31,"Flow_029nrs5 := Gateway_0xpxevh") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) + try: + Flow_029nrs5["id"] = Flow_029nrs5["id"] + 1 + except Exception as e: + __location = Location(282,282,9137,36,"Flow_029nrs5.id := Flow_029nrs5.id+1") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Flow_029nrs5) @staticmethod def execute_SupervisonModelImagingController_PrepareImaging_default_ImagingRequest(Gateway_0xpxevh): - ImagingRequest = {"cmd_type": "ImageEnum::PREPARE", "id": Gateway_0xpxevh["id"], "image_quality": "ImageQuality::NA"} + try: + ImagingRequest = {"cmd_type": "ImageEnum::PREPARE", "id": Gateway_0xpxevh["id"], "image_quality": "ImageQuality::NA"} + except Exception as e: + __location = Location(285,285,9246,117,"ImagingRequest := ImgReq { cmd_type = ImageEnum::PREPARE, id = Gateway_0xpxevh.id, image_quality = ImageQuality::NA }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(ImagingRequest) @staticmethod def execute_SupervisonModelImagingController_ImagingFinished_default_Flow_1k04xzh(Gateway_08l0os0,ImagingUpdate): - Flow_1k04xzh = Gateway_08l0os0 + try: + Flow_1k04xzh = Gateway_08l0os0 + except Exception as e: + __location = Location(293,293,9597,31,"Flow_1k04xzh := Gateway_08l0os0") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Flow_1k04xzh) @staticmethod def execute_SupervisonModelSupervisionPressureHandler_StartPump_default_Flow_0balrow(EqStatus,VacuumRequest,Gateway_1j81da5): - Flow_0balrow = Gateway_1j81da5 + try: + Flow_0balrow = Gateway_1j81da5 + except Exception as e: + __location = Location(332,332,10654,31,"Flow_0balrow := Gateway_1j81da5") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Flow_0balrow) @staticmethod def execute_SupervisonModelSupervisionPressureHandler_StartPump_default_PumpRequest(EqStatus,VacuumRequest,Gateway_1j81da5): - PumpRequest = {"cmd_type": "VacuumEnum::ON", "id": VacuumRequest["id"]} + try: + PumpRequest = {"cmd_type": "VacuumEnum::ON", "id": VacuumRequest["id"]} + except Exception as e: + __location = Location(335,338,10769,116,"PumpRequest := PumpReq { cmd_type = VacuumEnum::ON, id = VacuumRequest.id }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(PumpRequest) @staticmethod def execute_SupervisonModelSupervisionPressureHandler_StartPump_default_EqStatus(EqStatus,VacuumRequest,Gateway_1j81da5): - EqStatus = EqStatus + try: + EqStatus = EqStatus + except Exception as e: + __location = Location(341,341,10975,20,"EqStatus := EqStatus") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(EqStatus) @staticmethod def execute_SupervisonModelSupervisionPressureHandler_WaitforPumpOff_default_Gateway_1i0qy9g(PumpUpdate,EqStatus,Flow_0cjhiik): - Gateway_1i0qy9g = Flow_0cjhiik + try: + Gateway_1i0qy9g = Flow_0cjhiik + except Exception as e: + __location = Location(349,349,11236,31,"Gateway_1i0qy9g := Flow_0cjhiik") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Gateway_1i0qy9g) @staticmethod def execute_SupervisonModelSupervisionPressureHandler_WaitforPumpOff_default_EqStatus(PumpUpdate,EqStatus,Flow_0cjhiik): - EqStatus = {"temp_status": EqStatus["temp_status"], "pump_status": "Status::OFF", "acq_status": EqStatus["acq_status"]} + try: + EqStatus = {"temp_status": EqStatus["temp_status"], "pump_status": "Status::OFF", "acq_status": EqStatus["acq_status"]} + except Exception as e: + __location = Location(353,357,11373,182,"EqStatus := EquipmentStatus { temp_status = EqStatus.temp_status, pump_status = Status::OFF, acq_status = EqStatus.acq_status }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(EqStatus) @staticmethod def execute_SupervisonModelSupervisionPressureHandler_Restart_default_Gateway_1j81da5(Gateway_1i0qy9g): - Gateway_1j81da5 = Gateway_1i0qy9g + try: + Gateway_1j81da5 = Gateway_1i0qy9g + except Exception as e: + __location = Location(365,365,11760,34,"Gateway_1j81da5 := Gateway_1i0qy9g") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Gateway_1j81da5) @staticmethod def execute_SupervisonModelSupervisionPressureHandler_TurnOffPump_default_Flow_0cjhiik(Flow_1wguswc,EqStatus,VacuumRequest): - Flow_0cjhiik = Flow_1wguswc + try: + Flow_0cjhiik = Flow_1wguswc + except Exception as e: + __location = Location(374,374,12129,28,"Flow_0cjhiik := Flow_1wguswc") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Flow_0cjhiik) @staticmethod def execute_SupervisonModelSupervisionPressureHandler_TurnOffPump_default_PumpRequest(Flow_1wguswc,EqStatus,VacuumRequest): - PumpRequest = {"cmd_type": "VacuumEnum::OFF", "id": VacuumRequest["id"]} + try: + PumpRequest = {"cmd_type": "VacuumEnum::OFF", "id": VacuumRequest["id"]} + except Exception as e: + __location = Location(377,380,12241,117,"PumpRequest := PumpReq { cmd_type = VacuumEnum::OFF, id = VacuumRequest.id }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(PumpRequest) @staticmethod def execute_SupervisonModelSupervisionPressureHandler_TurnOffPump_default_EqStatus(Flow_1wguswc,EqStatus,VacuumRequest): - EqStatus = EqStatus + try: + EqStatus = EqStatus + except Exception as e: + __location = Location(383,383,12448,20,"EqStatus := EqStatus") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(EqStatus) @staticmethod def execute_SupervisonModelSupervisionPressureHandler_WaitforPumpStated_default_Flow_1wguswc(PumpUpdate,Flow_0balrow,EqStatus): - Flow_1wguswc = Flow_0balrow + try: + Flow_1wguswc = Flow_0balrow + except Exception as e: + __location = Location(391,391,12712,28,"Flow_1wguswc := Flow_0balrow") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Flow_1wguswc) @staticmethod def execute_SupervisonModelSupervisionPressureHandler_WaitforPumpStated_default_EqStatus(PumpUpdate,Flow_0balrow,EqStatus): - EqStatus = {"temp_status": EqStatus["temp_status"], "pump_status": "Status::ON", "acq_status": EqStatus["acq_status"]} + try: + EqStatus = {"temp_status": EqStatus["temp_status"], "pump_status": "Status::ON", "acq_status": EqStatus["acq_status"]} + except Exception as e: + __location = Location(395,399,12846,181,"EqStatus := EquipmentStatus { temp_status = EqStatus.temp_status, pump_status = Status::ON, acq_status = EqStatus.acq_status }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(EqStatus) @staticmethod def execute_SupervisonModelTemperatureController_return_default_Gateway_1sv33t8(Gateway_12yhscn): - Gateway_1sv33t8 = Gateway_12yhscn - Gateway_1sv33t8["id"] = Gateway_1sv33t8["id"] + try: + Gateway_1sv33t8 = Gateway_12yhscn + except Exception as e: + __location = Location(434,434,13845,34,"Gateway_1sv33t8 := Gateway_12yhscn") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) + try: + Gateway_1sv33t8["id"] = Gateway_1sv33t8["id"] + except Exception as e: + __location = Location(435,435,13893,40,"Gateway_1sv33t8.id := Gateway_1sv33t8.id") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Gateway_1sv33t8) @staticmethod def execute_SupervisonModelTemperatureController_CheckTemp_default_Flow_01g3o4k(Gateway_1sv33t8,temp_achieved): - Flow_01g3o4k = Gateway_1sv33t8 + try: + Flow_01g3o4k = Gateway_1sv33t8 + except Exception as e: + __location = Location(446,446,14300,31,"Flow_01g3o4k := Gateway_1sv33t8") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Flow_01g3o4k) @staticmethod def execute_SupervisonModelTemperatureController_SetTemperature_default_Flow_0estwso(Event_1r2zvr6): - Flow_0estwso = Event_1r2zvr6 - Flow_0estwso["id"] = Flow_0estwso["id"] + 1 + try: + Flow_0estwso = Event_1r2zvr6 + except Exception as e: + __location = Location(454,454,14546,29,"Flow_0estwso := Event_1r2zvr6") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) + try: + Flow_0estwso["id"] = Flow_0estwso["id"] + 1 + except Exception as e: + __location = Location(455,455,14589,38,"Flow_0estwso.id := Flow_0estwso.id + 1") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Flow_0estwso) @staticmethod def execute_SupervisonModelTemperatureController_SetTemperature_default_TempRequest(Event_1r2zvr6): - TempRequest = {"cmd_type": "TempEnum::SET", "id": Event_1r2zvr6["id"]} + try: + TempRequest = {"cmd_type": "TempEnum::SET", "id": Event_1r2zvr6["id"]} + except Exception as e: + __location = Location(458,461,14697,115,"TempRequest := TempReq { cmd_type = TempEnum::SET, id = Event_1r2zvr6.id }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(TempRequest) @staticmethod def execute_SupervisonModelTemperatureController_ResetTemperature_default_Flow_0ay6jpo(Flow_01g3o4k): - Flow_0ay6jpo = Flow_01g3o4k - Flow_0ay6jpo["id"] = Flow_0ay6jpo["id"] + 1 + try: + Flow_0ay6jpo = Flow_01g3o4k + except Exception as e: + __location = Location(469,469,15030,28,"Flow_0ay6jpo := Flow_01g3o4k") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) + try: + Flow_0ay6jpo["id"] = Flow_0ay6jpo["id"] + 1 + except Exception as e: + __location = Location(470,470,15072,38,"Flow_0ay6jpo.id := Flow_0ay6jpo.id + 1") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Flow_0ay6jpo) @staticmethod def execute_SupervisonModelTemperatureController_ResetTemperature_default_TempRequest(Flow_01g3o4k): - TempRequest = {"cmd_type": "TempEnum::RESET", "id": Flow_01g3o4k["id"]} + try: + TempRequest = {"cmd_type": "TempEnum::RESET", "id": Flow_01g3o4k["id"]} + except Exception as e: + __location = Location(473,476,15180,116,"TempRequest := TempReq { cmd_type = TempEnum::RESET, id = Flow_01g3o4k.id }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(TempRequest) @staticmethod def execute_SupervisonModelTemperatureController_WaitforReset_default_Gateway_12yhscn(Flow_0ay6jpo,TempUpdate): - Gateway_12yhscn = Flow_0ay6jpo + try: + Gateway_12yhscn = Flow_0ay6jpo + except Exception as e: + __location = Location(484,484,15522,31,"Gateway_12yhscn := Flow_0ay6jpo") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Gateway_12yhscn) @staticmethod def execute_SupervisonModelTemperatureController_WaitforTempSet_default_Gateway_1sv33t8(TempUpdate,Flow_0estwso): - Gateway_1sv33t8 = Flow_0estwso + try: + Gateway_1sv33t8 = Flow_0estwso + except Exception as e: + __location = Location(492,492,15784,31,"Gateway_1sv33t8 := Flow_0estwso") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Gateway_1sv33t8) @staticmethod def execute_SupervisonModelVacuumController_TurnOff_default_Flow_1dvvja5(Flow_1erv6vq): - Flow_1dvvja5 = Flow_1erv6vq - Flow_1dvvja5["id"] = Flow_1dvvja5["id"] + 1 + try: + Flow_1dvvja5 = Flow_1erv6vq + except Exception as e: + __location = Location(526,526,16566,28,"Flow_1dvvja5 := Flow_1erv6vq") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) + try: + Flow_1dvvja5["id"] = Flow_1dvvja5["id"] + 1 + except Exception as e: + __location = Location(527,527,16608,38,"Flow_1dvvja5.id := Flow_1dvvja5.id + 1") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Flow_1dvvja5) @staticmethod def execute_SupervisonModelVacuumController_TurnOff_default_VacuumRequest(Flow_1erv6vq): - VacuumRequest = {"cmd_type": "VacuumEnum::OFF", "id": Flow_1erv6vq["id"]} + try: + VacuumRequest = {"cmd_type": "VacuumEnum::OFF", "id": Flow_1erv6vq["id"]} + except Exception as e: + __location = Location(530,530,16718,76,"VacuumRequest := VacReq { cmd_type = VacuumEnum::OFF, id = Flow_1erv6vq.id }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(VacuumRequest) @staticmethod def execute_SupervisonModelVacuumController_SetVacuum_default_Flow_1phqrfh(Gateway_0mqr7c2): - Flow_1phqrfh = Gateway_0mqr7c2 - Flow_1phqrfh["id"] = Flow_1phqrfh["id"] + 1 + try: + Flow_1phqrfh = Gateway_0mqr7c2 + except Exception as e: + __location = Location(538,538,17001,31,"Flow_1phqrfh := Gateway_0mqr7c2") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) + try: + Flow_1phqrfh["id"] = Flow_1phqrfh["id"] + 1 + except Exception as e: + __location = Location(539,539,17046,38,"Flow_1phqrfh.id := Flow_1phqrfh.id + 1") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Flow_1phqrfh) @staticmethod def execute_SupervisonModelVacuumController_SetVacuum_default_VacuumRequest(Gateway_0mqr7c2): - VacuumRequest = {"cmd_type": "VacuumEnum::ON", "id": Gateway_0mqr7c2["id"]} + try: + VacuumRequest = {"cmd_type": "VacuumEnum::ON", "id": Gateway_0mqr7c2["id"]} + except Exception as e: + __location = Location(542,542,17156,78,"VacuumRequest := VacReq { cmd_type = VacuumEnum::ON, id = Gateway_0mqr7c2.id }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(VacuumRequest) @staticmethod def execute_SupervisonModelVacuumController_return_default_Gateway_0mqr7c2(Gateway_07w0e8f): - Gateway_0mqr7c2 = Gateway_07w0e8f + try: + Gateway_0mqr7c2 = Gateway_07w0e8f + except Exception as e: + __location = Location(550,550,17437,34,"Gateway_0mqr7c2 := Gateway_07w0e8f") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Gateway_0mqr7c2) @staticmethod def execute_SupervisonModelVacuumController_WaitforOff_default_Gateway_07w0e8f(VacuumUpdate,Flow_1dvvja5): - Gateway_07w0e8f = Flow_1dvvja5 + try: + Gateway_07w0e8f = Flow_1dvvja5 + except Exception as e: + __location = Location(558,558,17695,31,"Gateway_07w0e8f := Flow_1dvvja5") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Gateway_07w0e8f) @staticmethod def execute_SupervisonModelVacuumController_WaitforVacuumSet_default_Flow_1erv6vq(VacuumUpdate,Flow_1phqrfh): - Flow_1erv6vq = Flow_1phqrfh + try: + Flow_1erv6vq = Flow_1phqrfh + except Exception as e: + __location = Location(566,566,17960,28,"Flow_1erv6vq := Flow_1phqrfh") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Flow_1erv6vq) @staticmethod def execute_SupervisonModelAcquisitionController_AcquisitionStopped_default_Gateway_0h81kts(Flow_1w9tlf4): - Gateway_0h81kts = Flow_1w9tlf4 + try: + Gateway_0h81kts = Flow_1w9tlf4 + except Exception as e: + __location = Location(599,599,18726,31,"Gateway_0h81kts := Flow_1w9tlf4") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Gateway_0h81kts) @staticmethod def execute_SupervisonModelAcquisitionController_AcquisitionStopped_default_AcqUpdate(Flow_1w9tlf4): - AcqUpdate = {"result": "ResponseEnum::OK", "id": Flow_1w9tlf4["id"]} + try: + AcqUpdate = {"result": "ResponseEnum::OK", "id": Flow_1w9tlf4["id"]} + except Exception as e: + __location = Location(602,602,18825,72,"AcqUpdate := AcqResp { result = ResponseEnum::OK, id = Flow_1w9tlf4.id }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(AcqUpdate) @staticmethod def execute_SupervisonModelAcquisitionController_Execacquisitioninitandteardown_default_Flow_084nmm6(AcquisitionReq): - Flow_084nmm6 = {"id": AcquisitionReq["id"]} + try: + Flow_084nmm6 = {"id": AcquisitionReq["id"]} + except Exception as e: + __location = Location(611,611,19318,46,"Flow_084nmm6 := CTX { id = AcquisitionReq.id }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Flow_084nmm6) @staticmethod def execute_SupervisonModelAcquisitionController_StartAcquisition_default_Flow_1rusz82(AcquisitionReq): - Flow_1rusz82 = {"id": AcquisitionReq["id"]} + try: + Flow_1rusz82 = {"id": AcquisitionReq["id"]} + except Exception as e: + __location = Location(620,620,19700,46,"Flow_1rusz82 := CTX { id = AcquisitionReq.id }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Flow_1rusz82) @staticmethod def execute_SupervisonModelAcquisitionController_Acquisitionexecdone_default_Gateway_0h81kts(Flow_084nmm6): - Gateway_0h81kts = Flow_084nmm6 + try: + Gateway_0h81kts = Flow_084nmm6 + except Exception as e: + __location = Location(628,628,19974,31,"Gateway_0h81kts := Flow_084nmm6") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Gateway_0h81kts) @staticmethod def execute_SupervisonModelAcquisitionController_Acquisitionexecdone_default_AcqUpdate(Flow_084nmm6): - AcqUpdate = {"result": "ResponseEnum::OK", "id": Flow_084nmm6["id"]} + try: + AcqUpdate = {"result": "ResponseEnum::OK", "id": Flow_084nmm6["id"]} + except Exception as e: + __location = Location(631,631,20073,72,"AcqUpdate := AcqResp { result = ResponseEnum::OK, id = Flow_084nmm6.id }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(AcqUpdate) @staticmethod def execute_SupervisonModelAcquisitionController_StopAcquisition_default_Flow_1w9tlf4(AcquisitionReq): - Flow_1w9tlf4 = {"id": AcquisitionReq["id"]} + try: + Flow_1w9tlf4 = {"id": AcquisitionReq["id"]} + except Exception as e: + __location = Location(640,640,20478,46,"Flow_1w9tlf4 := CTX { id = AcquisitionReq.id }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Flow_1w9tlf4) @staticmethod def execute_SupervisonModelAcquisitionController_StopAcquisition_default_ImageData(AcquisitionReq): - ImageData = {"id": AcquisitionReq["id"]} + try: + ImageData = {"id": AcquisitionReq["id"]} + except Exception as e: + __location = Location(643,643,20606,47,"ImageData := AcqData { id = AcquisitionReq.id }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(ImageData) @staticmethod def execute_SupervisonModelAcquisitionController_AcquisitionStarted_default_Gateway_0h81kts(Flow_1rusz82): - Gateway_0h81kts = Flow_1rusz82 + try: + Gateway_0h81kts = Flow_1rusz82 + except Exception as e: + __location = Location(651,651,20878,31,"Gateway_0h81kts := Flow_1rusz82") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Gateway_0h81kts) @staticmethod def execute_SupervisonModelAcquisitionController_AcquisitionStarted_default_AcqUpdate(Flow_1rusz82): - AcqUpdate = {"result": "ResponseEnum::OK", "id": Flow_1rusz82["id"]} + try: + AcqUpdate = {"result": "ResponseEnum::OK", "id": Flow_1rusz82["id"]} + except Exception as e: + __location = Location(654,654,20977,72,"AcqUpdate := AcqResp { result = ResponseEnum::OK, id = Flow_1rusz82.id }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(AcqUpdate) @staticmethod def execute_SupervisonModelSupervisionImaging_WaitforStopAcquisition_default_Gateway_16m9e4j(AcqUpdate,Flow_0678bm1,EqStatus): - Gateway_16m9e4j = Flow_0678bm1 + try: + Gateway_16m9e4j = Flow_0678bm1 + except Exception as e: + __location = Location(693,693,22048,31,"Gateway_16m9e4j := Flow_0678bm1") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Gateway_16m9e4j) @staticmethod def execute_SupervisonModelSupervisionImaging_WaitforStopAcquisition_default_EqStatus(AcqUpdate,Flow_0678bm1,EqStatus): - EqStatus = {"temp_status": EqStatus["temp_status"], "pump_status": EqStatus["pump_status"], "acq_status": "Status::OFF"} + try: + EqStatus = {"temp_status": EqStatus["temp_status"], "pump_status": EqStatus["pump_status"], "acq_status": "Status::OFF"} + except Exception as e: + __location = Location(697,701,22186,183,"EqStatus := EquipmentStatus { temp_status = EqStatus.temp_status, pump_status = EqStatus.pump_status, acq_status = Status::OFF }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(EqStatus) @staticmethod def execute_SupervisonModelSupervisionImaging_CheckLowResImageQuality_default_Gateway_0qg69ul(ImageData,Gateway_16m9e4j,LastAcqReq): - Gateway_0qg69ul = Gateway_16m9e4j + try: + Gateway_0qg69ul = Gateway_16m9e4j + except Exception as e: + __location = Location(721,721,23105,34,"Gateway_0qg69ul := Gateway_16m9e4j") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Gateway_0qg69ul) @staticmethod def execute_SupervisonModelSupervisionImaging_WaitforStartAcquisition_default_Gateway_0qg69ul(AcqUpdate,EqStatus,Flow_1bajtwc): - Gateway_0qg69ul = Flow_1bajtwc + try: + Gateway_0qg69ul = Flow_1bajtwc + except Exception as e: + __location = Location(730,730,23464,31,"Gateway_0qg69ul := Flow_1bajtwc") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Gateway_0qg69ul) @staticmethod def execute_SupervisonModelSupervisionImaging_WaitforStartAcquisition_default_EqStatus(AcqUpdate,EqStatus,Flow_1bajtwc): - EqStatus = {"temp_status": EqStatus["temp_status"], "pump_status": EqStatus["pump_status"], "acq_status": "Status::ON"} + try: + EqStatus = {"temp_status": EqStatus["temp_status"], "pump_status": EqStatus["pump_status"], "acq_status": "Status::ON"} + except Exception as e: + __location = Location(734,738,23602,182,"EqStatus := EquipmentStatus { temp_status = EqStatus.temp_status, pump_status = EqStatus.pump_status, acq_status = Status::ON }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(EqStatus) @staticmethod def execute_SupervisonModelSupervisionImaging_StopAcquisition_default_AcquisitionReq(ImagingRequest): - AcquisitionReq = {"cmd_type": ImagingRequest["cmd_type"], "id": ImagingRequest["id"]} + try: + AcquisitionReq = {"cmd_type": ImagingRequest["cmd_type"], "id": ImagingRequest["id"]} + except Exception as e: + __location = Location(748,751,24165,128,"AcquisitionReq := AcqReq { cmd_type = ImagingRequest.cmd_type, id = ImagingRequest.id }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(AcquisitionReq) @staticmethod def execute_SupervisonModelSupervisionImaging_StartAcquisition_default_AcquisitionReq(ImagingRequest,EqStatus): - AcquisitionReq = {"cmd_type": ImagingRequest["cmd_type"], "id": ImagingRequest["id"]} + try: + AcquisitionReq = {"cmd_type": ImagingRequest["cmd_type"], "id": ImagingRequest["id"]} + except Exception as e: + __location = Location(761,764,24767,128,"AcquisitionReq := AcqReq { cmd_type = ImagingRequest.cmd_type, id = ImagingRequest.id }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(AcquisitionReq) @staticmethod def execute_SupervisonModelSupervisionImaging_StartAcquisition_default_LastAcqReq(ImagingRequest,EqStatus): - LastAcqReq = ImagingRequest + try: + LastAcqReq = ImagingRequest + except Exception as e: + __location = Location(767,767,24978,26,"LastAcqReq:=ImagingRequest") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(LastAcqReq) @staticmethod def execute_SupervisonModelSupervisionImaging_StartAcquisition_default_EqStatus(ImagingRequest,EqStatus): - EqStatus = EqStatus + try: + EqStatus = EqStatus + except Exception as e: + __location = Location(770,770,25094,20,"EqStatus := EqStatus") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(EqStatus) @staticmethod def execute_SupervisonModelSupervisionImaging_CheckHighResImageQuality_default_Gateway_0qg69ul(ImageData,Gateway_16m9e4j,LastAcqReq): - Gateway_0qg69ul = Gateway_16m9e4j + try: + Gateway_0qg69ul = Gateway_16m9e4j + except Exception as e: + __location = Location(790,790,25854,34,"Gateway_0qg69ul := Gateway_16m9e4j") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Gateway_0qg69ul) @staticmethod def execute_SupervisonModelSupervisionTemperatureHandler_CreateResetTempMessage_default_TempCMD(TempRequest,EqStatus): - TempCMD = TempRequest + try: + TempCMD = TempRequest + except Exception as e: + __location = Location(825,825,26908,22,"TempCMD := TempRequest") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(TempCMD) @staticmethod def execute_SupervisonModelSupervisionTemperatureHandler_CreateResetTempMessage_default_EqStatus(TempRequest,EqStatus): - EqStatus = EqStatus + try: + EqStatus = EqStatus + except Exception as e: + __location = Location(828,828,27020,20,"EqStatus := EqStatus") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(EqStatus) @staticmethod def execute_SupervisonModelSupervisionTemperatureHandler_ExecuteSetTemp_default_Event_13ys7sy(Gateway_1qk9wqe,EqStatus,TempCMD): - Event_13ys7sy = Gateway_1qk9wqe + try: + Event_13ys7sy = Gateway_1qk9wqe + except Exception as e: + __location = Location(836,836,27330,32,"Event_13ys7sy := Gateway_1qk9wqe") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Event_13ys7sy) @staticmethod def execute_SupervisonModelSupervisionTemperatureHandler_ExecuteSetTemp_default_temp_achieved(Gateway_1qk9wqe,EqStatus,TempCMD): - temp_achieved = {"result": "ResponseEnum::OK", "reqid": TempCMD["id"]} + try: + temp_achieved = {"result": "ResponseEnum::OK", "reqid": TempCMD["id"]} + except Exception as e: + __location = Location(840,843,27485,116,"temp_achieved := TempResp { result = ResponseEnum::OK, reqid = TempCMD.id }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(temp_achieved) @staticmethod def execute_SupervisonModelSupervisionTemperatureHandler_ExecuteSetTemp_default_EqStatus(Gateway_1qk9wqe,EqStatus,TempCMD): - EqStatus = {"temp_status": "Status::ON", "pump_status": EqStatus["pump_status"], "acq_status": EqStatus["acq_status"]} + try: + EqStatus = {"temp_status": "Status::ON", "pump_status": EqStatus["pump_status"], "acq_status": EqStatus["acq_status"]} + except Exception as e: + __location = Location(846,850,27682,181,"EqStatus := EquipmentStatus { temp_status = Status::ON, pump_status = EqStatus.pump_status, acq_status = EqStatus.acq_status }") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(EqStatus) @staticmethod def execute_SupervisonModelSupervisionTemperatureHandler_CreateSetTempMessage_default_TempCMD(TempRequest): - TempCMD = TempRequest + try: + TempCMD = TempRequest + except Exception as e: + __location = Location(860,860,28246,22,"TempCMD := TempRequest") + __source_file = "imaging.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(TempCMD) diff --git a/bundles/nl.asml.matala.product.tests/resources/expected/imaging/CPNServer/imaging/imaging_reporting.py b/bundles/nl.asml.matala.product.tests/resources/expected/imaging/CPNServer/imaging/imaging_reporting.py new file mode 100644 index 00000000..767fa104 --- /dev/null +++ b/bundles/nl.asml.matala.product.tests/resources/expected/imaging/CPNServer/imaging/imaging_reporting.py @@ -0,0 +1,153 @@ +import json +import traceback +from enum import Enum +from typing import List, Optional, Dict, Any +from dataclasses import dataclass, field +from pathlib import Path + +class StatusException(Exception): + def __init__(self, message: str): + super().__init__(message) + +class Severity(Enum): + OK = 0 + INFO = 1 + WARNING = 2 + ERROR = 3 + CANCEL = 4 + +@dataclass +class Location: + startLine: int + endLine: int + offset: int + length: int + text: str + + def to_dict(self) -> Dict[str, Any]: + return { + 'startLine': self.startLine, + 'endLine': self.endLine, + 'offset': self.offset, + 'length': self.length, + 'text': self.text, + } + +@dataclass +class StatusReport: + plugin: str + severity: Severity + message: str + source: str = "" + code: int = 0 + details: Optional[str] = None + location: Optional[Location] = None + children: List['StatusReport'] = field(default_factory=list) + exception: Optional[Exception] = field(default=None, repr=False) + + def __post_init__(self): + if self.exception is not None: + if self.details is None: + self.details = self._get_stack_trace_as_string(self.exception) + self.exception = None # Don't retain non-serializable object + + if self.children: + child_severities = [child.severity for child in self.children if child is not None] + if child_severities: + max_child_severity = max(child_severities, key=lambda s: s.value) + if max_child_severity.value > self.severity.value: + self.severity = max_child_severity + + @staticmethod + def _get_stack_trace_as_string(exception: Exception) -> str: + if exception is None: + return None + tb_lines = traceback.format_exception(type(exception), exception, exception.__traceback__) + if len(tb_lines) > 15: + tb_lines = tb_lines[:15] + [f"\t... {len(tb_lines) - 15} more\n"] + return "".join(tb_lines) + + def to_dict(self) -> Dict[str, Any]: + return { + 'plugin': self.plugin, + 'severity': self.severity.name, + 'message': self.message, + 'source': self.source, + 'code': self.code, + 'details': self.details, + 'location': self.location.to_dict() if self.location else None, + 'children': [child.to_dict() for child in self.children if child is not None], + } + +class StatusReporting: + def __init__(self, save_path: str): + self.save_path = Path(save_path) + self.reports: List[StatusReport] = [] + + def _log(self, severity: Severity, message: str, source: str = "", code: int = 0, + details: Optional[str] = None, exception: Optional[Exception] = None, location: Optional[Location] = None) -> StatusReport: + report = StatusReport( + plugin="", + severity=severity, + message=message, + source=source, + code=code, + details=details, + location=location, + exception=exception + ) + self.reports.append(report) + return report + + def info(self, message: str, source: str = "", code: int = 0, details: Optional[str] = None, location: Location = None) -> StatusReport: + return self._log(Severity.INFO, message, source, code, details, None, location) + + def warning(self, message: str, source: str = "", code: int = 0, details: Optional[str] = None, location: Location = None) -> StatusReport: + return self._log(Severity.WARNING, message, source, code, details, None, location) + + def error(self, message: str, source: str = "", code: int = 0, + details: Optional[str] = None, location: Location = None) -> StatusReport: + return self._log(Severity.ERROR, message, source, code, details, None, location) + + def exception(self, message: str, exception: Exception, source: str = "", details: str = None, code: int = 0, location: Location = None) -> StatusReport: + self._log(Severity.ERROR, message, source, code, details, exception, location) + #on exception the process is stopped + raise StatusException(message) + + def save(self) -> Severity: + + root_severity = Severity.OK + if self.reports: + root_severity = max((report.severity for report in self.reports), key=lambda s: s.value) + + root_report = StatusReport( + plugin="", + severity=root_severity, + message=f"Python generation of imaging", + source="", + code=0, + details=None, + location=None, + children=self.reports, + exception=None + ) + + data = root_report.to_dict() + with open(self.save_path, 'w') as f: + json.dump(data, f, indent=2) + + return root_severity + + +_status_reporting_instance: Optional[StatusReporting] = None + +def initialize_reporting(save_path: str) -> StatusReporting: + global _status_reporting_instance + _status_reporting_instance = StatusReporting(save_path) + return _status_reporting_instance + +def get_reporting() -> StatusReporting: + global _status_reporting_instance + if _status_reporting_instance is None: + raise RuntimeError("StatusReporting not initialized. Call initialize_reporting() first.") + return _status_reporting_instance diff --git a/bundles/nl.asml.matala.product.tests/resources/expected/issue371/CPNServer/issue371/issue371.py b/bundles/nl.asml.matala.product.tests/resources/expected/issue371/CPNServer/issue371/issue371.py index 029a734a..070891ac 100644 --- a/bundles/nl.asml.matala.product.tests/resources/expected/issue371/CPNServer/issue371/issue371.py +++ b/bundles/nl.asml.matala.product.tests/resources/expected/issue371/CPNServer/issue371/issue371.py @@ -10,10 +10,12 @@ if __package__ is None or __package__ == '': from issue371_TestSCN import TestSCN, Step, Tests, Constraint, CEntry from issue371_data import Data + from issue371_reporting import get_reporting, initialize_reporting, Location from issue371_Simulation import Simulation, simulate else: from .issue371_TestSCN import TestSCN, Step, Tests, Constraint, CEntry from .issue371_data import Data + from .issue371_reporting import get_reporting, initialize_reporting, Location from .issue371_Simulation import Simulation, simulate import subprocess import copy @@ -233,7 +235,8 @@ def initializeTestGeneration(self): if k + "_" +elm.__repr__() in self.map_transition_modes_to_name: print("WARN: duplicate modes detected for same transition.") print(k + "_" +elm.__repr__()) - print("WARN: references to the above transitions are ambigous!") + print("WARN: references to the above transitions are ambiguous!") + get_reporting().warning("Duplicate modes detected for same transition, Check References in Details", details=f"{k}_{str.join('\n',[str(s) for s in elm.items()])}") self.map_transition_modes_to_name[k + "_" +elm.__repr__()] = k + "_" + str(cnt) # self.map_transition_modes_to_name[k + "_" + pprint.pformat(elm.items(), width=60, compact=True,depth=5)] = k + "_" + str(cnt) cnt = cnt + 1 @@ -252,7 +255,7 @@ def generateTestCases(self): for entry in pn.visitedTList: # txt = '' if entry: - _test_scn = TestSCN(self.map_transition_assert, self.constraint_dict, self.tr_assert_ref_dict) + _test_scn = TestSCN(pspec_path, self.map_transition_assert, self.constraint_dict, self.tr_assert_ref_dict) idx = idx + 1 j = 0 for step in entry: @@ -340,103 +343,127 @@ def copy(self, name=None): type=bool, default=False, help="Disable simulation") - + + parser.add_argument("-srfile","--status_report_file", + type=Path, + default=None, + help="The path to where the status report will be saved") + + parser.add_argument("-pspath","--pspec_path", + type=str, + default="", + help="The relatve path to the pspec file to be used for test generation") + p = parser.parse_args() p.tspec_dir.mkdir(exist_ok=True) p.plantuml_dir.mkdir(exist_ok=True) - - a = datetime.datetime.now() - pn = issue371Model() - print("[INFO] Loaded CPN model.") - # pn.n.draw('net-gv-graph.png') - s = StateGraph(pn.n) - # s.build() - # s.draw('test-gv-graph.png') - # print(" Finished Generation, writing to file.. ") - print("[INFO] Starting Reachability Graph Generation") - # pn.generateScenarios(s,0,[],[],[],0,300) - sys.setrecursionlimit(400) - pn.generateSCN() - print('Num Tests: ', pn.numTestCases) - print("[INFO] Finished.") - b = datetime.datetime.now() + status_report_file = p.status_report_file if p.status_report_file != None else p.tspec_dir / "status_report.json" + status_report_file.parent.mkdir(parents=True, exist_ok=True) + pspec_path = p.pspec_path + reporting = initialize_reporting(status_report_file) - # s.goto(0) + try: + a = datetime.datetime.now() + pn = issue371Model() + print("[INFO] Loaded CPN model.") + # pn.n.draw('net-gv-graph.png') + s = StateGraph(pn.n) + # s.build() + # s.draw('test-gv-graph.png') + # print(" Finished Generation, writing to file.. ") + print("[INFO] Starting Reachability Graph Generation") + # pn.generateScenarios(s,0,[],[],[],0,300) + sys.setrecursionlimit(400) + pn.generateSCN() + print('Num Tests: ', pn.numTestCases) + print("[INFO] Finished.") + b = datetime.datetime.now() - fname = p.plantuml_dir / "rg.plantuml" - with open(fname, 'w') as f: - pn.generateReachabilityGraph(f) - print("[INFO] Created %s" % (fname,)) - c = datetime.datetime.now() - - print("[INFO] Starting Test Generation.") - pn.initializeTestGeneration() - pn.generateTestCases() - - # print('[INFO] Number-of-generated-scenario files: ',len(pn.visitedTList)) - print("[INFO] Test Generation Finished.") - d = datetime.datetime.now() + # s.goto(0) + + fname = p.plantuml_dir / "rg.plantuml" + with open(fname, 'w') as f: + pn.generateReachabilityGraph(f) + print("[INFO] Created %s" % (fname,)) + c = datetime.datetime.now() - print("[INFO] Creating Structure and Behavior Views in PlantUML.") - map_block_uml_txt = {} - for t in pn.n.transition(): - map_block_uml_txt[t.name.split('_')[0]] = '@startuml\n' + print("[INFO] Starting Test Generation.") + pn.initializeTestGeneration() + pn.generateTestCases() - for t in pn.n.transition(): - gtxt = map_block_uml_txt.get(t.name.split('_')[0]) - if 'json.loads' in t.guard._str: - # print(t.guard._str.replace('json.loads','')) - # print('\n'.join(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),55)))) - gtxt += 'component %s\n' % (t.name) - if len(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),68))) <= 2: - gtxt += 'note left of [%s]\n %s\nendnote\n' % (t.name, '\n'.join(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),55)))) - else: - gtxt += 'note bottom of [%s]\n %s\nendnote\n' % (t.name, '\n'.join(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),55)))) - else: - gtxt += 'component %s\n' % (t.name) - gtxt += 'note right of [%s]\n %s\nendnote\n' % (t.name, t.guard) - map_block_uml_txt[t.name.split('_')[0]] = gtxt + # print('[INFO] Number-of-generated-scenario files: ',len(pn.visitedTList)) + print("[INFO] Test Generation Finished.") + d = datetime.datetime.now() - for t in pn.n.transition(): - for inp in pn.n.pre(t.name): - txt = map_block_uml_txt.get(t.name.split('_')[0]) - if 'local' in inp: - txt += '%s -[#lightgrey]-> [%s]\n' % (inp, t.name) + print("[INFO] Creating Structure and Behavior Views in PlantUML.") + map_block_uml_txt = {} + for t in pn.n.transition(): + map_block_uml_txt[t.name.split('_')[0]] = '@startuml\n' + + for t in pn.n.transition(): + gtxt = map_block_uml_txt.get(t.name.split('_')[0]) + if 'json.loads' in t.guard._str: + # print(t.guard._str.replace('json.loads','')) + # print('\n'.join(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),55)))) + gtxt += 'component %s\n' % (t.name) + if len(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),68))) <= 2: + gtxt += 'note left of [%s]\n %s\nendnote\n' % (t.name, '\n'.join(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),55)))) + else: + gtxt += 'note bottom of [%s]\n %s\nendnote\n' % (t.name, '\n'.join(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),55)))) else: - txt += '%s --> [%s]\n' % (inp, t.name) - map_block_uml_txt[t.name.split('_')[0]] = txt - for out in pn.n.post(t.name): - txt = map_block_uml_txt.get(t.name.split('_')[0]) - if 'local' in out: - txt += '[%s] -[#lightgrey]-> %s\n' % (t.name, out) - else: - txt += '[%s] --> %s\n' % (t.name, out) - map_block_uml_txt[t.name.split('_')[0]] = txt - - for key in map_block_uml_txt: - txt = map_block_uml_txt.get(key) - txt += '@enduml\n' - map_block_uml_txt[key] = txt - fname = p.plantuml_dir / (key + ".plantuml") - with open(fname, 'w') as f: - f.write(txt) - - print("[INFO] View Generation Finished.") - e = datetime.datetime.now() - print("[INFO] Time Statistics") - print("[INFO] * Reachability Computation: %s" % (b - a)) - print("[INFO] * Reachability PUML Creation: %s" % (c - b)) - print("[INFO] * Test Generation: %s" % (d - c)) - print("[INFO] * PlantUML View Generation: %s" % (e - d)) - - # print("[INFO] Starting Command-Line Simulation.") - # simulate(pn.n) - - #if not p.no_sim: - # print('[SIM] Start Simulation? (Y/N) :') - # value = input(" Enter Choice: ") - # if value == "Y" or value == "y": - # os.system('cls') - # simulate(pn.n) - - print("[INFO] Exiting..") + gtxt += 'component %s\n' % (t.name) + gtxt += 'note right of [%s]\n %s\nendnote\n' % (t.name, t.guard) + map_block_uml_txt[t.name.split('_')[0]] = gtxt + + for t in pn.n.transition(): + for inp in pn.n.pre(t.name): + txt = map_block_uml_txt.get(t.name.split('_')[0]) + if 'local' in inp: + txt += '%s -[#lightgrey]-> [%s]\n' % (inp, t.name) + else: + txt += '%s --> [%s]\n' % (inp, t.name) + map_block_uml_txt[t.name.split('_')[0]] = txt + for out in pn.n.post(t.name): + txt = map_block_uml_txt.get(t.name.split('_')[0]) + if 'local' in out: + txt += '[%s] -[#lightgrey]-> %s\n' % (t.name, out) + else: + txt += '[%s] --> %s\n' % (t.name, out) + map_block_uml_txt[t.name.split('_')[0]] = txt + + for key in map_block_uml_txt: + txt = map_block_uml_txt.get(key) + txt += '@enduml\n' + map_block_uml_txt[key] = txt + fname = p.plantuml_dir / (key + ".plantuml") + with open(fname, 'w') as f: + f.write(txt) + + print("[INFO] View Generation Finished.") + e = datetime.datetime.now() + print("[INFO] Time Statistics") + print("[INFO] * Reachability Computation: %s" % (b - a)) + print("[INFO] * Reachability PUML Creation: %s" % (c - b)) + print("[INFO] * Test Generation: %s" % (d - c)) + print("[INFO] * PlantUML View Generation: %s" % (e - d)) + + # print("[INFO] Starting Command-Line Simulation.") + # simulate(pn.n) + + #if not p.no_sim: + # print('[SIM] Start Simulation? (Y/N) :') + # value = input(" Enter Choice: ") + # if value == "Y" or value == "y": + # os.system('cls') + # simulate(pn.n) + + except Exception as e: + print("[ERROR] " + str(e)) + if not isinstance(e, StatusException): + get_reporting().exception(message = e.__class__.__name__, exception = e) + finally: + print("[INFO] Saving status_report.json") + severity = reporting.save() + print("[INFO] Saved status_report.json") + print(f"[INFO] Exiting with status: {severity.name}") + exit(severity.value) diff --git a/bundles/nl.asml.matala.product.tests/resources/expected/issue371/CPNServer/issue371/issue371_TestSCN.py b/bundles/nl.asml.matala.product.tests/resources/expected/issue371/CPNServer/issue371/issue371_TestSCN.py index 26b4b647..f2427ed0 100644 --- a/bundles/nl.asml.matala.product.tests/resources/expected/issue371/CPNServer/issue371/issue371_TestSCN.py +++ b/bundles/nl.asml.matala.product.tests/resources/expected/issue371/CPNServer/issue371/issue371_TestSCN.py @@ -22,12 +22,13 @@ class TestSCN: constraint_dict = {} tr_assert_ref_dict = {} - def __init__(self, _mapTrAssert, _constraint_dict, _tr_assert_ref_dict): + def __init__(self, _pspec_path, _mapTrAssert, _constraint_dict, _tr_assert_ref_dict): self.step_list = [] self.step_dependencies = [] self.map_transition_assert = _mapTrAssert self.constraint_dict = _constraint_dict self.tr_assert_ref_dict = _tr_assert_ref_dict + self.pspec_path = _pspec_path def generate_viz(self, idx, output_dir): txt = "@startuml\n" @@ -73,7 +74,7 @@ def recurseJson(self, items, prefix): raise TypeError('Unsupported type') txt += f" {prefix} := {items}\n" return txt - + def printData(self, idata): txt = "" for k, v in idata.items(): @@ -83,10 +84,10 @@ def printData(self, idata): # for jk in j.keys(): # txt += self.recurseJson(j[jk], "%s.%s" % (k,jk)) return txt - + def generateTSpec(self, idx, sutTypesList, sutVarTransitionMap, transitionQnameMap, output_dir): txt = "" - txt += "import \"issue371.ps\"\n\n" + txt += f"""import "{self.pspec_path}issue371.ps"\n\n""" txt += "using issue371.Root.Event_0o4qsh5\n" txt += "using issue371.Root.Event_1bks5sc\n" txt += "\nabstract-test-definition\n\n" @@ -297,8 +298,8 @@ class CEntry: name = "" constr = "" + def __init__(self, n, c): self.name = n self.constr = c - diff --git a/bundles/nl.asml.matala.product.tests/resources/expected/issue371/CPNServer/issue371/issue371_data.py b/bundles/nl.asml.matala.product.tests/resources/expected/issue371/CPNServer/issue371/issue371_data.py index 1084dfb2..d2756afa 100644 --- a/bundles/nl.asml.matala.product.tests/resources/expected/issue371/CPNServer/issue371/issue371_data.py +++ b/bundles/nl.asml.matala.product.tests/resources/expected/issue371/CPNServer/issue371/issue371_data.py @@ -1,6 +1,9 @@ import copy import json - +if __package__ is None or __package__ == '': + from issue371_reporting import get_reporting, Location +else: + from .issue371_reporting import get_reporting, Location class Data: @@ -25,14 +28,34 @@ def get_MyContext(): @staticmethod def execute_Root_T1_default_Event_1bks5sc(Event_0o4qsh5): - Event_1bks5sc = Event_0o4qsh5 - if True: - pass - else: - pass - for i in list(range(2)): - pass - if not (False): - Event_1bks5sc["myField"] = 1 + try: + Event_1bks5sc = Event_0o4qsh5 + except Exception as e: + __location = Location(26,26,510,30,"Event_1bks5sc := Event_0o4qsh5") + __source_file = "issue371.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) + try: + if True: + pass + else: + pass + except Exception as e: + __location = Location(27,31,554,94,"if true then // Empty else // Empty fi") + __source_file = "issue371.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) + try: + for i in list(range(2)): + pass + except Exception as e: + __location = Location(32,34,662,69,"for int i in range(2) do // Empty end-for") + __source_file = "issue371.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) + try: + if not (False): + Event_1bks5sc["myField"] = 1 + except Exception as e: + __location = Location(35,37,745,75,"if not false then Event_1bks5sc.myField := 1 fi") + __source_file = "issue371.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Event_1bks5sc) diff --git a/bundles/nl.asml.matala.product.tests/resources/expected/issue371/CPNServer/issue371/issue371_reporting.py b/bundles/nl.asml.matala.product.tests/resources/expected/issue371/CPNServer/issue371/issue371_reporting.py new file mode 100644 index 00000000..44e1d050 --- /dev/null +++ b/bundles/nl.asml.matala.product.tests/resources/expected/issue371/CPNServer/issue371/issue371_reporting.py @@ -0,0 +1,153 @@ +import json +import traceback +from enum import Enum +from typing import List, Optional, Dict, Any +from dataclasses import dataclass, field +from pathlib import Path + +class StatusException(Exception): + def __init__(self, message: str): + super().__init__(message) + +class Severity(Enum): + OK = 0 + INFO = 1 + WARNING = 2 + ERROR = 3 + CANCEL = 4 + +@dataclass +class Location: + startLine: int + endLine: int + offset: int + length: int + text: str + + def to_dict(self) -> Dict[str, Any]: + return { + 'startLine': self.startLine, + 'endLine': self.endLine, + 'offset': self.offset, + 'length': self.length, + 'text': self.text, + } + +@dataclass +class StatusReport: + plugin: str + severity: Severity + message: str + source: str = "" + code: int = 0 + details: Optional[str] = None + location: Optional[Location] = None + children: List['StatusReport'] = field(default_factory=list) + exception: Optional[Exception] = field(default=None, repr=False) + + def __post_init__(self): + if self.exception is not None: + if self.details is None: + self.details = self._get_stack_trace_as_string(self.exception) + self.exception = None # Don't retain non-serializable object + + if self.children: + child_severities = [child.severity for child in self.children if child is not None] + if child_severities: + max_child_severity = max(child_severities, key=lambda s: s.value) + if max_child_severity.value > self.severity.value: + self.severity = max_child_severity + + @staticmethod + def _get_stack_trace_as_string(exception: Exception) -> str: + if exception is None: + return None + tb_lines = traceback.format_exception(type(exception), exception, exception.__traceback__) + if len(tb_lines) > 15: + tb_lines = tb_lines[:15] + [f"\t... {len(tb_lines) - 15} more\n"] + return "".join(tb_lines) + + def to_dict(self) -> Dict[str, Any]: + return { + 'plugin': self.plugin, + 'severity': self.severity.name, + 'message': self.message, + 'source': self.source, + 'code': self.code, + 'details': self.details, + 'location': self.location.to_dict() if self.location else None, + 'children': [child.to_dict() for child in self.children if child is not None], + } + +class StatusReporting: + def __init__(self, save_path: str): + self.save_path = Path(save_path) + self.reports: List[StatusReport] = [] + + def _log(self, severity: Severity, message: str, source: str = "", code: int = 0, + details: Optional[str] = None, exception: Optional[Exception] = None, location: Optional[Location] = None) -> StatusReport: + report = StatusReport( + plugin="", + severity=severity, + message=message, + source=source, + code=code, + details=details, + location=location, + exception=exception + ) + self.reports.append(report) + return report + + def info(self, message: str, source: str = "", code: int = 0, details: Optional[str] = None, location: Location = None) -> StatusReport: + return self._log(Severity.INFO, message, source, code, details, None, location) + + def warning(self, message: str, source: str = "", code: int = 0, details: Optional[str] = None, location: Location = None) -> StatusReport: + return self._log(Severity.WARNING, message, source, code, details, None, location) + + def error(self, message: str, source: str = "", code: int = 0, + details: Optional[str] = None, location: Location = None) -> StatusReport: + return self._log(Severity.ERROR, message, source, code, details, None, location) + + def exception(self, message: str, exception: Exception, source: str = "", details: str = None, code: int = 0, location: Location = None) -> StatusReport: + self._log(Severity.ERROR, message, source, code, details, exception, location) + #on exception the process is stopped + raise StatusException(message) + + def save(self) -> Severity: + + root_severity = Severity.OK + if self.reports: + root_severity = max((report.severity for report in self.reports), key=lambda s: s.value) + + root_report = StatusReport( + plugin="", + severity=root_severity, + message=f"Python generation of issue371", + source="", + code=0, + details=None, + location=None, + children=self.reports, + exception=None + ) + + data = root_report.to_dict() + with open(self.save_path, 'w') as f: + json.dump(data, f, indent=2) + + return root_severity + + +_status_reporting_instance: Optional[StatusReporting] = None + +def initialize_reporting(save_path: str) -> StatusReporting: + global _status_reporting_instance + _status_reporting_instance = StatusReporting(save_path) + return _status_reporting_instance + +def get_reporting() -> StatusReporting: + global _status_reporting_instance + if _status_reporting_instance is None: + raise RuntimeError("StatusReporting not initialized. Call initialize_reporting() first.") + return _status_reporting_instance diff --git a/bundles/nl.asml.matala.product.tests/resources/expected/printer/CPNServer/printer/printer.py b/bundles/nl.asml.matala.product.tests/resources/expected/printer/CPNServer/printer/printer.py index f3c0985d..fa6f8395 100644 --- a/bundles/nl.asml.matala.product.tests/resources/expected/printer/CPNServer/printer/printer.py +++ b/bundles/nl.asml.matala.product.tests/resources/expected/printer/CPNServer/printer/printer.py @@ -10,10 +10,12 @@ if __package__ is None or __package__ == '': from printer_TestSCN import TestSCN, Step, Tests, Constraint, CEntry from printer_data import Data + from printer_reporting import get_reporting, initialize_reporting, Location from printer_Simulation import Simulation, simulate else: from .printer_TestSCN import TestSCN, Step, Tests, Constraint, CEntry from .printer_data import Data + from .printer_reporting import get_reporting, initialize_reporting, Location from .printer_Simulation import Simulation, simulate import subprocess import copy @@ -372,7 +374,8 @@ def initializeTestGeneration(self): if k + "_" +elm.__repr__() in self.map_transition_modes_to_name: print("WARN: duplicate modes detected for same transition.") print(k + "_" +elm.__repr__()) - print("WARN: references to the above transitions are ambigous!") + print("WARN: references to the above transitions are ambiguous!") + get_reporting().warning("Duplicate modes detected for same transition, Check References in Details", details=f"{k}_{str.join('\n',[str(s) for s in elm.items()])}") self.map_transition_modes_to_name[k + "_" +elm.__repr__()] = k + "_" + str(cnt) # self.map_transition_modes_to_name[k + "_" + pprint.pformat(elm.items(), width=60, compact=True,depth=5)] = k + "_" + str(cnt) cnt = cnt + 1 @@ -401,7 +404,7 @@ def generateTestCases(self): for entry in pn.visitedTList: # txt = '' if entry: - _test_scn = TestSCN(self.map_transition_assert, self.constraint_dict, self.tr_assert_ref_dict) + _test_scn = TestSCN(pspec_path, self.map_transition_assert, self.constraint_dict, self.tr_assert_ref_dict) idx = idx + 1 j = 0 for step in entry: @@ -489,103 +492,127 @@ def copy(self, name=None): type=bool, default=False, help="Disable simulation") - + + parser.add_argument("-srfile","--status_report_file", + type=Path, + default=None, + help="The path to where the status report will be saved") + + parser.add_argument("-pspath","--pspec_path", + type=str, + default="", + help="The relatve path to the pspec file to be used for test generation") + p = parser.parse_args() p.tspec_dir.mkdir(exist_ok=True) p.plantuml_dir.mkdir(exist_ok=True) - - a = datetime.datetime.now() - pn = printerModel() - print("[INFO] Loaded CPN model.") - # pn.n.draw('net-gv-graph.png') - s = StateGraph(pn.n) - # s.build() - # s.draw('test-gv-graph.png') - # print(" Finished Generation, writing to file.. ") - print("[INFO] Starting Reachability Graph Generation") - # pn.generateScenarios(s,0,[],[],[],0,300) - sys.setrecursionlimit(400) - pn.generateSCN() - print('Num Tests: ', pn.numTestCases) - print("[INFO] Finished.") - b = datetime.datetime.now() + status_report_file = p.status_report_file if p.status_report_file != None else p.tspec_dir / "status_report.json" + status_report_file.parent.mkdir(parents=True, exist_ok=True) + pspec_path = p.pspec_path + reporting = initialize_reporting(status_report_file) - # s.goto(0) + try: + a = datetime.datetime.now() + pn = printerModel() + print("[INFO] Loaded CPN model.") + # pn.n.draw('net-gv-graph.png') + s = StateGraph(pn.n) + # s.build() + # s.draw('test-gv-graph.png') + # print(" Finished Generation, writing to file.. ") + print("[INFO] Starting Reachability Graph Generation") + # pn.generateScenarios(s,0,[],[],[],0,300) + sys.setrecursionlimit(400) + pn.generateSCN() + print('Num Tests: ', pn.numTestCases) + print("[INFO] Finished.") + b = datetime.datetime.now() - fname = p.plantuml_dir / "rg.plantuml" - with open(fname, 'w') as f: - pn.generateReachabilityGraph(f) - print("[INFO] Created %s" % (fname,)) - c = datetime.datetime.now() - - print("[INFO] Starting Test Generation.") - pn.initializeTestGeneration() - pn.generateTestCases() - - # print('[INFO] Number-of-generated-scenario files: ',len(pn.visitedTList)) - print("[INFO] Test Generation Finished.") - d = datetime.datetime.now() + # s.goto(0) + + fname = p.plantuml_dir / "rg.plantuml" + with open(fname, 'w') as f: + pn.generateReachabilityGraph(f) + print("[INFO] Created %s" % (fname,)) + c = datetime.datetime.now() - print("[INFO] Creating Structure and Behavior Views in PlantUML.") - map_block_uml_txt = {} - for t in pn.n.transition(): - map_block_uml_txt[t.name.split('_')[0]] = '@startuml\n' + print("[INFO] Starting Test Generation.") + pn.initializeTestGeneration() + pn.generateTestCases() - for t in pn.n.transition(): - gtxt = map_block_uml_txt.get(t.name.split('_')[0]) - if 'json.loads' in t.guard._str: - # print(t.guard._str.replace('json.loads','')) - # print('\n'.join(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),55)))) - gtxt += 'component %s\n' % (t.name) - if len(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),68))) <= 2: - gtxt += 'note left of [%s]\n %s\nendnote\n' % (t.name, '\n'.join(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),55)))) - else: - gtxt += 'note bottom of [%s]\n %s\nendnote\n' % (t.name, '\n'.join(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),55)))) - else: - gtxt += 'component %s\n' % (t.name) - gtxt += 'note right of [%s]\n %s\nendnote\n' % (t.name, t.guard) - map_block_uml_txt[t.name.split('_')[0]] = gtxt + # print('[INFO] Number-of-generated-scenario files: ',len(pn.visitedTList)) + print("[INFO] Test Generation Finished.") + d = datetime.datetime.now() - for t in pn.n.transition(): - for inp in pn.n.pre(t.name): - txt = map_block_uml_txt.get(t.name.split('_')[0]) - if 'local' in inp: - txt += '%s -[#lightgrey]-> [%s]\n' % (inp, t.name) + print("[INFO] Creating Structure and Behavior Views in PlantUML.") + map_block_uml_txt = {} + for t in pn.n.transition(): + map_block_uml_txt[t.name.split('_')[0]] = '@startuml\n' + + for t in pn.n.transition(): + gtxt = map_block_uml_txt.get(t.name.split('_')[0]) + if 'json.loads' in t.guard._str: + # print(t.guard._str.replace('json.loads','')) + # print('\n'.join(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),55)))) + gtxt += 'component %s\n' % (t.name) + if len(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),68))) <= 2: + gtxt += 'note left of [%s]\n %s\nendnote\n' % (t.name, '\n'.join(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),55)))) + else: + gtxt += 'note bottom of [%s]\n %s\nendnote\n' % (t.name, '\n'.join(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),55)))) else: - txt += '%s --> [%s]\n' % (inp, t.name) - map_block_uml_txt[t.name.split('_')[0]] = txt - for out in pn.n.post(t.name): - txt = map_block_uml_txt.get(t.name.split('_')[0]) - if 'local' in out: - txt += '[%s] -[#lightgrey]-> %s\n' % (t.name, out) - else: - txt += '[%s] --> %s\n' % (t.name, out) - map_block_uml_txt[t.name.split('_')[0]] = txt - - for key in map_block_uml_txt: - txt = map_block_uml_txt.get(key) - txt += '@enduml\n' - map_block_uml_txt[key] = txt - fname = p.plantuml_dir / (key + ".plantuml") - with open(fname, 'w') as f: - f.write(txt) - - print("[INFO] View Generation Finished.") - e = datetime.datetime.now() - print("[INFO] Time Statistics") - print("[INFO] * Reachability Computation: %s" % (b - a)) - print("[INFO] * Reachability PUML Creation: %s" % (c - b)) - print("[INFO] * Test Generation: %s" % (d - c)) - print("[INFO] * PlantUML View Generation: %s" % (e - d)) - - # print("[INFO] Starting Command-Line Simulation.") - # simulate(pn.n) - - #if not p.no_sim: - # print('[SIM] Start Simulation? (Y/N) :') - # value = input(" Enter Choice: ") - # if value == "Y" or value == "y": - # os.system('cls') - # simulate(pn.n) - - print("[INFO] Exiting..") + gtxt += 'component %s\n' % (t.name) + gtxt += 'note right of [%s]\n %s\nendnote\n' % (t.name, t.guard) + map_block_uml_txt[t.name.split('_')[0]] = gtxt + + for t in pn.n.transition(): + for inp in pn.n.pre(t.name): + txt = map_block_uml_txt.get(t.name.split('_')[0]) + if 'local' in inp: + txt += '%s -[#lightgrey]-> [%s]\n' % (inp, t.name) + else: + txt += '%s --> [%s]\n' % (inp, t.name) + map_block_uml_txt[t.name.split('_')[0]] = txt + for out in pn.n.post(t.name): + txt = map_block_uml_txt.get(t.name.split('_')[0]) + if 'local' in out: + txt += '[%s] -[#lightgrey]-> %s\n' % (t.name, out) + else: + txt += '[%s] --> %s\n' % (t.name, out) + map_block_uml_txt[t.name.split('_')[0]] = txt + + for key in map_block_uml_txt: + txt = map_block_uml_txt.get(key) + txt += '@enduml\n' + map_block_uml_txt[key] = txt + fname = p.plantuml_dir / (key + ".plantuml") + with open(fname, 'w') as f: + f.write(txt) + + print("[INFO] View Generation Finished.") + e = datetime.datetime.now() + print("[INFO] Time Statistics") + print("[INFO] * Reachability Computation: %s" % (b - a)) + print("[INFO] * Reachability PUML Creation: %s" % (c - b)) + print("[INFO] * Test Generation: %s" % (d - c)) + print("[INFO] * PlantUML View Generation: %s" % (e - d)) + + # print("[INFO] Starting Command-Line Simulation.") + # simulate(pn.n) + + #if not p.no_sim: + # print('[SIM] Start Simulation? (Y/N) :') + # value = input(" Enter Choice: ") + # if value == "Y" or value == "y": + # os.system('cls') + # simulate(pn.n) + + except Exception as e: + print("[ERROR] " + str(e)) + if not isinstance(e, StatusException): + get_reporting().exception(message = e.__class__.__name__, exception = e) + finally: + print("[INFO] Saving status_report.json") + severity = reporting.save() + print("[INFO] Saved status_report.json") + print(f"[INFO] Exiting with status: {severity.name}") + exit(severity.value) diff --git a/bundles/nl.asml.matala.product.tests/resources/expected/printer/CPNServer/printer/printer_TestSCN.py b/bundles/nl.asml.matala.product.tests/resources/expected/printer/CPNServer/printer/printer_TestSCN.py index 0a1cb6be..0ec6f35a 100644 --- a/bundles/nl.asml.matala.product.tests/resources/expected/printer/CPNServer/printer/printer_TestSCN.py +++ b/bundles/nl.asml.matala.product.tests/resources/expected/printer/CPNServer/printer/printer_TestSCN.py @@ -22,12 +22,13 @@ class TestSCN: constraint_dict = {} tr_assert_ref_dict = {} - def __init__(self, _mapTrAssert, _constraint_dict, _tr_assert_ref_dict): + def __init__(self, _pspec_path, _mapTrAssert, _constraint_dict, _tr_assert_ref_dict): self.step_list = [] self.step_dependencies = [] self.map_transition_assert = _mapTrAssert self.constraint_dict = _constraint_dict self.tr_assert_ref_dict = _tr_assert_ref_dict + self.pspec_path = _pspec_path def generate_viz(self, idx, output_dir): txt = "@startuml\n" @@ -73,7 +74,7 @@ def recurseJson(self, items, prefix): raise TypeError('Unsupported type') txt += f" {prefix} := {items}\n" return txt - + def printData(self, idata): txt = "" for k, v in idata.items(): @@ -83,10 +84,10 @@ def printData(self, idata): # for jk in j.keys(): # txt += self.recurseJson(j[jk], "%s.%s" % (k,jk)) return txt - + def generateTSpec(self, idx, sutTypesList, sutVarTransitionMap, transitionQnameMap, output_dir): txt = "" - txt += "import \"printer.ps\"\n\n" + txt += f"""import "{self.pspec_path}printer.ps"\n\n""" txt += "using printer.PrintFactoryA3DPrinter.printJob\n" txt += "using printer.PrintFactoryA3DPrinter.corrections\n" txt += "using printer.PrintFactoryA3DPrinter.variants\n" @@ -330,8 +331,8 @@ class CEntry: name = "" constr = "" + def __init__(self, n, c): self.name = n self.constr = c - diff --git a/bundles/nl.asml.matala.product.tests/resources/expected/printer/CPNServer/printer/printer_data.py b/bundles/nl.asml.matala.product.tests/resources/expected/printer/CPNServer/printer/printer_data.py index f9e363a2..f111b292 100644 --- a/bundles/nl.asml.matala.product.tests/resources/expected/printer/CPNServer/printer/printer_data.py +++ b/bundles/nl.asml.matala.product.tests/resources/expected/printer/CPNServer/printer/printer_data.py @@ -1,6 +1,9 @@ import copy import json - +if __package__ is None or __package__ == '': + from printer_reporting import get_reporting, Location +else: + from .printer_reporting import get_reporting, Location class Data: @@ -77,180 +80,375 @@ def get_Result(): @staticmethod def execute_PrintFactoryA3DPrinter_RunPrintJob_default_Event_0jcg6zx(request,Flow_1u2qmtt,variants): - Event_0jcg6zx = Flow_1u2qmtt + try: + Event_0jcg6zx = Flow_1u2qmtt + except Exception as e: + __location = Location(64,64,2157,29,"Event_0jcg6zx := Flow_1u2qmtt") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Event_0jcg6zx) @staticmethod def execute_PrintFactoryA3DPrinter_RunPrintJob_default_printResult(request,Flow_1u2qmtt,variants): - printResult = {"verdict": "Outcome::OK"} + try: + printResult = {"verdict": "Outcome::OK"} + except Exception as e: + __location = Location(67,67,2256,47,"printResult := Result { verdict = Outcome::OK }") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(printResult) @staticmethod def execute_PrintFactoryA3DPrinter_RunPrintJob_default_printReport(request,Flow_1u2qmtt,variants): - printReport = {"id": request["id"]} + try: + printReport = {"id": request["id"]} + except Exception as e: + __location = Location(70,72,2412,68,"printReport := Report { id = request.id }") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(printReport) @staticmethod def execute_PrintFactoryA3DPrinter_RunPrintJob_default_variants(request,Flow_1u2qmtt,variants): - variants = variants + try: + variants = variants + except Exception as e: + __location = Location(75,75,2561,20,"variants := variants") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(variants) @staticmethod def execute_PrintFactoryA3DPrinter_ComposePrintJob_default_request(corrections,printJob): - request = printJob + try: + request = printJob + except Exception as e: + __location = Location(85,85,2996,19,"request := printJob") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(request) @staticmethod def execute_PrintFactoryA3DPrinter_ComposePrepareJob_default_request(printJob): - request = printJob + try: + request = printJob + except Exception as e: + __location = Location(95,95,3386,19,"request := printJob") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(request) @staticmethod def execute_PrintFactoryA3DPrinter_RunPrepareJob_default_Event_0mxx05p(request,Flow_0iaelzn,variants): - Event_0mxx05p = Flow_0iaelzn + try: + Event_0mxx05p = Flow_0iaelzn + except Exception as e: + __location = Location(106,106,3888,29,"Event_0mxx05p := Flow_0iaelzn") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Event_0mxx05p) @staticmethod def execute_PrintFactoryA3DPrinter_RunPrepareJob_default_printResult(request,Flow_0iaelzn,variants): - printResult = {"verdict": "Outcome::OK"} + try: + printResult = {"verdict": "Outcome::OK"} + except Exception as e: + __location = Location(109,109,3987,47,"printResult := Result { verdict = Outcome::OK }") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(printResult) @staticmethod def execute_PrintFactoryA3DPrinter_RunPrepareJob_default_variants(request,Flow_0iaelzn,variants): - variants = variants + try: + variants = variants + except Exception as e: + __location = Location(112,112,4115,20,"variants := variants") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(variants) @staticmethod def execute_PrintFactoryAssertions_AssertVisualInspection_default_history(inspectionReport,history): - history = {"inspectionReports": history["inspectionReports"] + [inspectionReport["id"]]} + try: + history = {"inspectionReports": history["inspectionReports"] + [inspectionReport["id"]]} + except Exception as e: + __location = Location(149,151,5220,132,"history := AssertionsHistory { inspectionReports = add(history.inspectionReports, inspectionReport.id) }") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(history) @staticmethod def execute_PrintFactoryAssertions_AssertVisualInspection_default_inspectionReport(inspectionReport,history): - inspectionReport = inspectionReport + try: + inspectionReport = inspectionReport + except Exception as e: + __location = Location(154,154,5471,36,"inspectionReport := inspectionReport") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(inspectionReport) @staticmethod def execute_PrintFactoryInspection_RunVisualinspection_default_inspectionReport(measureRequest,Flow_07l0yyj): - inspectionReport = {"id": measureRequest["id"]} + try: + inspectionReport = {"id": measureRequest["id"]} + except Exception as e: + __location = Location(187,189,6351,80,"inspectionReport := Report { id = measureRequest.id }") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(inspectionReport) @staticmethod def execute_PrintFactoryInspection_RunVisualinspection_default_inspectionResult(measureRequest,Flow_07l0yyj): - inspectionResult = {"verdict": "Outcome::OK"} + try: + inspectionResult = {"verdict": "Outcome::OK"} + except Exception as e: + __location = Location(192,192,6506,52,"inspectionResult := Result { verdict = Outcome::OK }") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(inspectionResult) @staticmethod def execute_PrintFactoryInspection_ComposeVisualInspectionJob_default_measureRequest(printReport,inspectionJob): - measureRequest = inspectionJob + try: + measureRequest = inspectionJob + except Exception as e: + __location = Location(205,205,7118,31,"measureRequest := inspectionJob") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(measureRequest) @staticmethod def execute_PrintFactoryInspection_ComposeVisualInspectionJob_default_printReport(printReport,inspectionJob): - printReport = printReport + try: + printReport = printReport + except Exception as e: + __location = Location(208,208,7242,26,"printReport := printReport") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(printReport) @staticmethod def execute_PrintFactoryOptimization_ComposeOptimizationJob_default_optimizeJob(optJob,inspectionReport): - optimizeJob = optJob + try: + optimizeJob = optJob + except Exception as e: + __location = Location(243,243,8195,21,"optimizeJob := optJob") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(optimizeJob) @staticmethod def execute_PrintFactoryOptimization_ComposeOptimizationJob_default_inspectionReport(optJob,inspectionReport): - inspectionReport = inspectionReport + try: + inspectionReport = inspectionReport + except Exception as e: + __location = Location(246,246,8314,36,"inspectionReport := inspectionReport") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(inspectionReport) @staticmethod def execute_PrintFactoryOptimization_RunOptimizationJob_default_Event_1oozdnw(optimizeJob,Flow_0y8u5pd): - Event_1oozdnw = Flow_0y8u5pd + try: + Event_1oozdnw = Flow_0y8u5pd + except Exception as e: + __location = Location(254,254,8641,29,"Event_1oozdnw := Flow_0y8u5pd") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Event_1oozdnw) @staticmethod def execute_PrintFactoryOptimization_RunOptimizationJob_default_corrections(optimizeJob,Flow_0y8u5pd): - corrections = {"id": optimizeJob["id"] + 1} + try: + corrections = {"id": optimizeJob["id"] + 1} + except Exception as e: + __location = Location(257,259,8754,87,"corrections := CorrectionsReport { id = optimizeJob.id + 1 }") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(corrections) @staticmethod def execute_PrintFactoryFactoryAutomation_SendPrintJob_default_Flow_16s4ey1(printRequests,Gateway_1wpvmtk): - Flow_16s4ey1 = Gateway_1wpvmtk - Flow_16s4ey1["color"] = printRequests["color"] - Flow_16s4ey1["resolution"] = printRequests["resolution"] - Flow_16s4ey1["scale"] = printRequests["scale"] + try: + Flow_16s4ey1 = Gateway_1wpvmtk + except Exception as e: + __location = Location(335,335,10947,31,"Flow_16s4ey1 := Gateway_1wpvmtk") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) + try: + Flow_16s4ey1["color"] = printRequests["color"] + except Exception as e: + __location = Location(336,336,10992,41,"Flow_16s4ey1.color := printRequests.color") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) + try: + Flow_16s4ey1["resolution"] = printRequests["resolution"] + except Exception as e: + __location = Location(337,337,11047,51,"Flow_16s4ey1.resolution := printRequests.resolution") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) + try: + Flow_16s4ey1["scale"] = printRequests["scale"] + except Exception as e: + __location = Location(338,338,11112,41,"Flow_16s4ey1.scale := printRequests.scale") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Flow_16s4ey1) @staticmethod def execute_PrintFactoryFactoryAutomation_SendPrintJob_default_printJob(printRequests,Gateway_1wpvmtk): - printJob = {"id": printRequests["id"], "resolution": printRequests["resolution"], "scale": printRequests["scale"], "color": printRequests["color"], "opType": printRequests["opType"]} + try: + printJob = {"id": printRequests["id"], "resolution": printRequests["resolution"], "scale": printRequests["scale"], "color": printRequests["color"], "opType": printRequests["opType"]} + except Exception as e: + __location = Location(341,347,11220,261,"printJob := PrintRequest { id = printRequests.id, resolution = printRequests.resolution, scale = printRequests.scale, color = printRequests.color, opType = printRequests.opType }") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(printJob) @staticmethod def execute_PrintFactoryFactoryAutomation_NextJob_default_Gateway_1wpvmtk(Gateway_0p2uo9v): - Gateway_1wpvmtk = Gateway_0p2uo9v - Gateway_1wpvmtk["id"] = Gateway_1wpvmtk["id"] + 1 + try: + Gateway_1wpvmtk = Gateway_0p2uo9v + except Exception as e: + __location = Location(355,355,11687,34,"Gateway_1wpvmtk := Gateway_0p2uo9v") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) + try: + Gateway_1wpvmtk["id"] = Gateway_1wpvmtk["id"] + 1 + except Exception as e: + __location = Location(356,356,11735,44,"Gateway_1wpvmtk.id := Gateway_1wpvmtk.id + 1") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Gateway_1wpvmtk) @staticmethod def execute_PrintFactoryFactoryAutomation_WaitforOptimizationJob_default_Flow_09b0flo(Flow_01m2s0h,optResult): - Flow_09b0flo = Flow_01m2s0h + try: + Flow_09b0flo = Flow_01m2s0h + except Exception as e: + __location = Location(364,364,12022,28,"Flow_09b0flo := Flow_01m2s0h") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Flow_09b0flo) @staticmethod def execute_PrintFactoryFactoryAutomation_Gateway_1f8wap6_default_Gateway_0p2uo9v(Flow_09b0flo,Flow_1vq9t2p): - Gateway_0p2uo9v = Flow_09b0flo + try: + Gateway_0p2uo9v = Flow_09b0flo + except Exception as e: + __location = Location(373,373,12332,31,"Gateway_0p2uo9v := Flow_09b0flo") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Gateway_0p2uo9v) @staticmethod def execute_PrintFactoryFactoryAutomation_Gateway_1j3rupx_default_Flow_1y4bjf4(Flow_1dcdx0e): - Flow_1y4bjf4 = Flow_1dcdx0e + try: + Flow_1y4bjf4 = Flow_1dcdx0e + except Exception as e: + __location = Location(381,381,12578,28,"Flow_1y4bjf4 := Flow_1dcdx0e") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Flow_1y4bjf4) @staticmethod def execute_PrintFactoryFactoryAutomation_Gateway_1j3rupx_default_Flow_1f74bn4(Flow_1dcdx0e): - Flow_1f74bn4 = Flow_1dcdx0e + try: + Flow_1f74bn4 = Flow_1dcdx0e + except Exception as e: + __location = Location(384,384,12677,28,"Flow_1f74bn4 := Flow_1dcdx0e") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Flow_1f74bn4) @staticmethod def execute_PrintFactoryFactoryAutomation_WaitforVisualInspection_default_Flow_0kbycuh(inspectionResult,Flow_1dt29vl): - Flow_0kbycuh = Flow_1dt29vl + try: + Flow_0kbycuh = Flow_1dt29vl + except Exception as e: + __location = Location(392,392,12957,28,"Flow_0kbycuh := Flow_1dt29vl") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Flow_0kbycuh) @staticmethod def execute_PrintFactoryFactoryAutomation_SendOptimizationJob_default_Flow_01m2s0h(Flow_0kbycuh): - Flow_01m2s0h = Flow_0kbycuh + try: + Flow_01m2s0h = Flow_0kbycuh + except Exception as e: + __location = Location(400,400,13210,28,"Flow_01m2s0h := Flow_0kbycuh") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Flow_01m2s0h) @staticmethod def execute_PrintFactoryFactoryAutomation_SendOptimizationJob_default_optJob(Flow_0kbycuh): - optJob = {"id": Flow_0kbycuh["id"]} + try: + optJob = {"id": Flow_0kbycuh["id"]} + except Exception as e: + __location = Location(403,403,13303,50,"optJob := OptimizeRequest { id = Flow_0kbycuh.id }") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(optJob) @staticmethod def execute_PrintFactoryFactoryAutomation_CleanPrinter_default_Flow_1rkhqnd(Flow_1f74bn4): - Flow_1rkhqnd = Flow_1f74bn4 + try: + Flow_1rkhqnd = Flow_1f74bn4 + except Exception as e: + __location = Location(411,411,13563,28,"Flow_1rkhqnd := Flow_1f74bn4") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Flow_1rkhqnd) @staticmethod def execute_PrintFactoryFactoryAutomation_CleanPrinter_default_printJob(Flow_1f74bn4): - printJob = {"id": Flow_1f74bn4["id"], "resolution": Flow_1f74bn4["resolution"], "scale": None, "color": Flow_1f74bn4["color"], "opType": "OperationType::PREP"} + try: + printJob = {"id": Flow_1f74bn4["id"], "resolution": Flow_1f74bn4["resolution"], "scale": None, "color": Flow_1f74bn4["color"], "opType": "OperationType::PREP"} + except Exception as e: + __location = Location(414,420,13658,242,"printJob := PrintRequest { id = Flow_1f74bn4.id, resolution = Flow_1f74bn4.resolution, scale = null, color = Flow_1f74bn4.color, opType = OperationType::PREP }") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(printJob) @staticmethod def execute_PrintFactoryFactoryAutomation_SendVisualInspectionJob_default_Flow_1dt29vl(Flow_1y4bjf4): - Flow_1dt29vl = Flow_1y4bjf4 + try: + Flow_1dt29vl = Flow_1y4bjf4 + except Exception as e: + __location = Location(428,428,14134,28,"Flow_1dt29vl := Flow_1y4bjf4") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Flow_1dt29vl) @staticmethod def execute_PrintFactoryFactoryAutomation_SendVisualInspectionJob_default_inspectionJob(Flow_1y4bjf4): - inspectionJob = {"id": Flow_1y4bjf4["id"]} + try: + inspectionJob = {"id": Flow_1y4bjf4["id"]} + except Exception as e: + __location = Location(431,433,14276,83,"inspectionJob := MeasureRequest { id = Flow_1y4bjf4.id }") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(inspectionJob) @staticmethod def execute_PrintFactoryFactoryAutomation_WaitforClean_default_Flow_1vq9t2p(printResult,Flow_1rkhqnd): - Flow_1vq9t2p = Flow_1rkhqnd + try: + Flow_1vq9t2p = Flow_1rkhqnd + except Exception as e: + __location = Location(441,441,14583,28,"Flow_1vq9t2p := Flow_1rkhqnd") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Flow_1vq9t2p) @staticmethod def execute_PrintFactoryFactoryAutomation_WaitforPrintJob_default_Flow_1dcdx0e(printResult,Flow_16s4ey1): - Flow_1dcdx0e = Flow_16s4ey1 + try: + Flow_1dcdx0e = Flow_16s4ey1 + except Exception as e: + __location = Location(449,449,14842,28,"Flow_1dcdx0e := Flow_16s4ey1") + __source_file = "printer.ps" + get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location) return json.dumps(Flow_1dcdx0e) diff --git a/bundles/nl.asml.matala.product.tests/resources/expected/printer/CPNServer/printer/printer_reporting.py b/bundles/nl.asml.matala.product.tests/resources/expected/printer/CPNServer/printer/printer_reporting.py new file mode 100644 index 00000000..4164612b --- /dev/null +++ b/bundles/nl.asml.matala.product.tests/resources/expected/printer/CPNServer/printer/printer_reporting.py @@ -0,0 +1,153 @@ +import json +import traceback +from enum import Enum +from typing import List, Optional, Dict, Any +from dataclasses import dataclass, field +from pathlib import Path + +class StatusException(Exception): + def __init__(self, message: str): + super().__init__(message) + +class Severity(Enum): + OK = 0 + INFO = 1 + WARNING = 2 + ERROR = 3 + CANCEL = 4 + +@dataclass +class Location: + startLine: int + endLine: int + offset: int + length: int + text: str + + def to_dict(self) -> Dict[str, Any]: + return { + 'startLine': self.startLine, + 'endLine': self.endLine, + 'offset': self.offset, + 'length': self.length, + 'text': self.text, + } + +@dataclass +class StatusReport: + plugin: str + severity: Severity + message: str + source: str = "" + code: int = 0 + details: Optional[str] = None + location: Optional[Location] = None + children: List['StatusReport'] = field(default_factory=list) + exception: Optional[Exception] = field(default=None, repr=False) + + def __post_init__(self): + if self.exception is not None: + if self.details is None: + self.details = self._get_stack_trace_as_string(self.exception) + self.exception = None # Don't retain non-serializable object + + if self.children: + child_severities = [child.severity for child in self.children if child is not None] + if child_severities: + max_child_severity = max(child_severities, key=lambda s: s.value) + if max_child_severity.value > self.severity.value: + self.severity = max_child_severity + + @staticmethod + def _get_stack_trace_as_string(exception: Exception) -> str: + if exception is None: + return None + tb_lines = traceback.format_exception(type(exception), exception, exception.__traceback__) + if len(tb_lines) > 15: + tb_lines = tb_lines[:15] + [f"\t... {len(tb_lines) - 15} more\n"] + return "".join(tb_lines) + + def to_dict(self) -> Dict[str, Any]: + return { + 'plugin': self.plugin, + 'severity': self.severity.name, + 'message': self.message, + 'source': self.source, + 'code': self.code, + 'details': self.details, + 'location': self.location.to_dict() if self.location else None, + 'children': [child.to_dict() for child in self.children if child is not None], + } + +class StatusReporting: + def __init__(self, save_path: str): + self.save_path = Path(save_path) + self.reports: List[StatusReport] = [] + + def _log(self, severity: Severity, message: str, source: str = "", code: int = 0, + details: Optional[str] = None, exception: Optional[Exception] = None, location: Optional[Location] = None) -> StatusReport: + report = StatusReport( + plugin="", + severity=severity, + message=message, + source=source, + code=code, + details=details, + location=location, + exception=exception + ) + self.reports.append(report) + return report + + def info(self, message: str, source: str = "", code: int = 0, details: Optional[str] = None, location: Location = None) -> StatusReport: + return self._log(Severity.INFO, message, source, code, details, None, location) + + def warning(self, message: str, source: str = "", code: int = 0, details: Optional[str] = None, location: Location = None) -> StatusReport: + return self._log(Severity.WARNING, message, source, code, details, None, location) + + def error(self, message: str, source: str = "", code: int = 0, + details: Optional[str] = None, location: Location = None) -> StatusReport: + return self._log(Severity.ERROR, message, source, code, details, None, location) + + def exception(self, message: str, exception: Exception, source: str = "", details: str = None, code: int = 0, location: Location = None) -> StatusReport: + self._log(Severity.ERROR, message, source, code, details, exception, location) + #on exception the process is stopped + raise StatusException(message) + + def save(self) -> Severity: + + root_severity = Severity.OK + if self.reports: + root_severity = max((report.severity for report in self.reports), key=lambda s: s.value) + + root_report = StatusReport( + plugin="", + severity=root_severity, + message=f"Python generation of printer", + source="", + code=0, + details=None, + location=None, + children=self.reports, + exception=None + ) + + data = root_report.to_dict() + with open(self.save_path, 'w') as f: + json.dump(data, f, indent=2) + + return root_severity + + +_status_reporting_instance: Optional[StatusReporting] = None + +def initialize_reporting(save_path: str) -> StatusReporting: + global _status_reporting_instance + _status_reporting_instance = StatusReporting(save_path) + return _status_reporting_instance + +def get_reporting() -> StatusReporting: + global _status_reporting_instance + if _status_reporting_instance is None: + raise RuntimeError("StatusReporting not initialized. Call initialize_reporting() first.") + return _status_reporting_instance diff --git a/bundles/nl.asml.matala.product/src/nl/asml/matala/product/generator/PetriNet.xtend b/bundles/nl.asml.matala.product/src/nl/asml/matala/product/generator/PetriNet.xtend index b349cb70..af7cc3df 100644 --- a/bundles/nl.asml.matala.product/src/nl/asml/matala/product/generator/PetriNet.xtend +++ b/bundles/nl.asml.matala.product/src/nl/asml/matala/product/generator/PetriNet.xtend @@ -353,10 +353,12 @@ class PetriNet { if __package__ is None or __package__ == '': from «prod_name»_TestSCN import TestSCN, Step, Tests, Constraint, CEntry from «prod_name»_data import Data + from «prod_name»_reporting import get_reporting, initialize_reporting, Location from «prod_name»_Simulation import Simulation, simulate else: from .«prod_name»_TestSCN import TestSCN, Step, Tests, Constraint, CEntry from .«prod_name»_data import Data + from .«prod_name»_reporting import get_reporting, initialize_reporting, Location from .«prod_name»_Simulation import Simulation, simulate import subprocess import copy @@ -433,7 +435,8 @@ class PetriNet { if k + "_" +elm.__repr__() in self.map_transition_modes_to_name: print("WARN: duplicate modes detected for same transition.") print(k + "_" +elm.__repr__()) - print("WARN: references to the above transitions are ambigous!") + print("WARN: references to the above transitions are ambiguous!") + get_reporting().warning("Duplicate modes detected for same transition, Check References in Details", details=f"{k}_{str.join('\n',[str(s) for s in elm.items()])}") self.map_transition_modes_to_name[k + "_" +elm.__repr__()] = k + "_" + str(cnt) # self.map_transition_modes_to_name[k + "_" + pprint.pformat(elm.items(), width=60, compact=True,depth=5)] = k + "_" + str(cnt) cnt = cnt + 1 @@ -470,7 +473,7 @@ class PetriNet { for entry in pn.visitedTList: # txt = '' if entry: - _test_scn = TestSCN(self.map_transition_assert, self.constraint_dict, self.tr_assert_ref_dict) + _test_scn = TestSCN(pspec_path, self.map_transition_assert, self.constraint_dict, self.tr_assert_ref_dict) idx = idx + 1 j = 0 for step in entry: @@ -558,106 +561,130 @@ class PetriNet { type=bool, default=False, help="Disable simulation") - + + parser.add_argument("-srfile","--status_report_file", + type=Path, + default=None, + help="The path to where the status report will be saved") + + parser.add_argument("-pspath","--pspec_path", + type=str, + default="", + help="The relatve path to the pspec file to be used for test generation") + p = parser.parse_args() p.tspec_dir.mkdir(exist_ok=True) p.plantuml_dir.mkdir(exist_ok=True) + status_report_file = p.status_report_file if p.status_report_file != None else p.tspec_dir / "status_report.json" + status_report_file.parent.mkdir(parents=True, exist_ok=True) + pspec_path = p.pspec_path + reporting = initialize_reporting(status_report_file) + + try: + a = datetime.datetime.now() + pn = «prod_name»Model() + print("[INFO] Loaded CPN model.") + # pn.n.draw('net-gv-graph.png') + s = StateGraph(pn.n) + # s.build() + # s.draw('test-gv-graph.png') + # print(" Finished Generation, writing to file.. ") + print("[INFO] Starting Reachability Graph Generation") + # pn.generateScenarios(s,0,[],[],[],0,«depth_limit») + sys.setrecursionlimit(«depth_limit + 100») + pn.generateSCN() + print('Num Tests: ', pn.numTestCases) + print("[INFO] Finished.") + b = datetime.datetime.now() - a = datetime.datetime.now() - pn = «prod_name»Model() - print("[INFO] Loaded CPN model.") - # pn.n.draw('net-gv-graph.png') - s = StateGraph(pn.n) - # s.build() - # s.draw('test-gv-graph.png') - # print(" Finished Generation, writing to file.. ") - print("[INFO] Starting Reachability Graph Generation") - # pn.generateScenarios(s,0,[],[],[],0,«depth_limit») - sys.setrecursionlimit(«depth_limit + 100») - pn.generateSCN() - print('Num Tests: ', pn.numTestCases) - print("[INFO] Finished.") - b = datetime.datetime.now() - - # s.goto(0) - - fname = p.plantuml_dir / "rg.plantuml" - with open(fname, 'w') as f: - pn.generateReachabilityGraph(f) - print("[INFO] Created %s" % (fname,)) - c = datetime.datetime.now() - - print("[INFO] Starting Test Generation.") - pn.initializeTestGeneration() - pn.generateTestCases() - - # print('[INFO] Number-of-generated-scenario files: ',len(pn.visitedTList)) - print("[INFO] Test Generation Finished.") - d = datetime.datetime.now() + # s.goto(0) + + fname = p.plantuml_dir / "rg.plantuml" + with open(fname, 'w') as f: + pn.generateReachabilityGraph(f) + print("[INFO] Created %s" % (fname,)) + c = datetime.datetime.now() - print("[INFO] Creating Structure and Behavior Views in PlantUML.") - map_block_uml_txt = {} - for t in pn.n.transition(): - map_block_uml_txt[t.name.split('_')[0]] = '@startuml\n' + print("[INFO] Starting Test Generation.") + pn.initializeTestGeneration() + pn.generateTestCases() - for t in pn.n.transition(): - gtxt = map_block_uml_txt.get(t.name.split('_')[0]) - if 'json.loads' in t.guard._str: - # print(t.guard._str.replace('json.loads','')) - # print('\n'.join(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),55)))) - gtxt += 'component %s\n' % (t.name) - if len(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),68))) <= 2: - gtxt += 'note left of [%s]\n %s\nendnote\n' % (t.name, '\n'.join(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),55)))) - else: - gtxt += 'note bottom of [%s]\n %s\nendnote\n' % (t.name, '\n'.join(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),55)))) - else: - gtxt += 'component %s\n' % (t.name) - gtxt += 'note right of [%s]\n %s\nendnote\n' % (t.name, t.guard) - map_block_uml_txt[t.name.split('_')[0]] = gtxt + # print('[INFO] Number-of-generated-scenario files: ',len(pn.visitedTList)) + print("[INFO] Test Generation Finished.") + d = datetime.datetime.now() - for t in pn.n.transition(): - for inp in pn.n.pre(t.name): - txt = map_block_uml_txt.get(t.name.split('_')[0]) - if 'local' in inp: - txt += '%s -[#lightgrey]-> [%s]\n' % (inp, t.name) - else: - txt += '%s --> [%s]\n' % (inp, t.name) - map_block_uml_txt[t.name.split('_')[0]] = txt - for out in pn.n.post(t.name): - txt = map_block_uml_txt.get(t.name.split('_')[0]) - if 'local' in out: - txt += '[%s] -[#lightgrey]-> %s\n' % (t.name, out) + print("[INFO] Creating Structure and Behavior Views in PlantUML.") + map_block_uml_txt = {} + for t in pn.n.transition(): + map_block_uml_txt[t.name.split('_')[0]] = '@startuml\n' + + for t in pn.n.transition(): + gtxt = map_block_uml_txt.get(t.name.split('_')[0]) + if 'json.loads' in t.guard._str: + # print(t.guard._str.replace('json.loads','')) + # print('\n'.join(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),55)))) + gtxt += 'component %s\n' % (t.name) + if len(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),68))) <= 2: + gtxt += 'note left of [%s]\n %s\nendnote\n' % (t.name, '\n'.join(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),55)))) + else: + gtxt += 'note bottom of [%s]\n %s\nendnote\n' % (t.name, '\n'.join(list(pn.chunkstring(t.guard._str.replace('json.loads','').replace(', object_pairs_hook=Data().int_keys', ''),55)))) else: - txt += '[%s] --> %s\n' % (t.name, out) - map_block_uml_txt[t.name.split('_')[0]] = txt - - for key in map_block_uml_txt: - txt = map_block_uml_txt.get(key) - txt += '@enduml\n' - map_block_uml_txt[key] = txt - fname = p.plantuml_dir / (key + ".plantuml") - with open(fname, 'w') as f: - f.write(txt) - - print("[INFO] View Generation Finished.") - e = datetime.datetime.now() - print("[INFO] Time Statistics") - print("[INFO] * Reachability Computation: %s" % (b - a)) - print("[INFO] * Reachability PUML Creation: %s" % (c - b)) - print("[INFO] * Test Generation: %s" % (d - c)) - print("[INFO] * PlantUML View Generation: %s" % (e - d)) - - # print("[INFO] Starting Command-Line Simulation.") - # simulate(pn.n) - - #if not p.no_sim: - # print('[SIM] Start Simulation? (Y/N) :') - # value = input(" Enter Choice: ") - # if value == "Y" or value == "y": - # os.system('cls') - # simulate(pn.n) - - print("[INFO] Exiting..") + gtxt += 'component %s\n' % (t.name) + gtxt += 'note right of [%s]\n %s\nendnote\n' % (t.name, t.guard) + map_block_uml_txt[t.name.split('_')[0]] = gtxt + + for t in pn.n.transition(): + for inp in pn.n.pre(t.name): + txt = map_block_uml_txt.get(t.name.split('_')[0]) + if 'local' in inp: + txt += '%s -[#lightgrey]-> [%s]\n' % (inp, t.name) + else: + txt += '%s --> [%s]\n' % (inp, t.name) + map_block_uml_txt[t.name.split('_')[0]] = txt + for out in pn.n.post(t.name): + txt = map_block_uml_txt.get(t.name.split('_')[0]) + if 'local' in out: + txt += '[%s] -[#lightgrey]-> %s\n' % (t.name, out) + else: + txt += '[%s] --> %s\n' % (t.name, out) + map_block_uml_txt[t.name.split('_')[0]] = txt + + for key in map_block_uml_txt: + txt = map_block_uml_txt.get(key) + txt += '@enduml\n' + map_block_uml_txt[key] = txt + fname = p.plantuml_dir / (key + ".plantuml") + with open(fname, 'w') as f: + f.write(txt) + + print("[INFO] View Generation Finished.") + e = datetime.datetime.now() + print("[INFO] Time Statistics") + print("[INFO] * Reachability Computation: %s" % (b - a)) + print("[INFO] * Reachability PUML Creation: %s" % (c - b)) + print("[INFO] * Test Generation: %s" % (d - c)) + print("[INFO] * PlantUML View Generation: %s" % (e - d)) + + # print("[INFO] Starting Command-Line Simulation.") + # simulate(pn.n) + + #if not p.no_sim: + # print('[SIM] Start Simulation? (Y/N) :') + # value = input(" Enter Choice: ") + # if value == "Y" or value == "y": + # os.system('cls') + # simulate(pn.n) + + except Exception as e: + print("[ERROR] " + str(e)) + if not isinstance(e, StatusException): + get_reporting().exception(message = e.__class__.__name__, exception = e) + finally: + print("[INFO] Saving status_report.json") + severity = reporting.save() + print("[INFO] Saved status_report.json") + print(f"[INFO] Exiting with status: {severity.name}") + exit(severity.value) ''' def print_SCNGen(int num_tests, int depth_limit, int state_limit) ''' diff --git a/bundles/nl.asml.matala.product/src/nl/asml/matala/product/generator/ProductGenerator.xtend b/bundles/nl.asml.matala.product/src/nl/asml/matala/product/generator/ProductGenerator.xtend index 6b2eee2e..9c37e836 100644 --- a/bundles/nl.asml.matala.product/src/nl/asml/matala/product/generator/ProductGenerator.xtend +++ b/bundles/nl.asml.matala.product/src/nl/asml/matala/product/generator/ProductGenerator.xtend @@ -174,9 +174,9 @@ class ProductGenerator extends AbstractGenerator { init_places, depth_limit, state_limit, num_tests, sutTransitionMap )) fsa.generateFile('CPNServer//' + specName + '//' + specName + '_Simulation.py', pnet.toSnakesSimulation) - - fsa.generateFile('CPNServer//' + specName + '//' + specName + '_data.py', (new Utils()).getDataContainerClass(dataGetterTxt, methodTxt)) - fsa.generateFile('CPNServer//' + specName + '//' + specName + '_TestSCN.py', (new Utils()).generateTestSCNTxt(specName + "_types", prod, resource.URI.lastSegment)) + fsa.generateFile('CPNServer//' + specName + '//' + specName + '_reporting.py', Utils.getReportingClass(specName)) + fsa.generateFile('CPNServer//' + specName + '//' + specName + '_data.py', Utils.getDataContainerClass(specName, dataGetterTxt, methodTxt)) + fsa.generateFile('CPNServer//' + specName + '//' + specName + '_TestSCN.py', Utils.generateTestSCNTxt(specName + "_types", prod, resource.URI.lastSegment)) // generate utils for HTTP server fsa.generateFile('CPNServer//' + specName + '//' + '__init__.py', (new FlaskSimulationGenerator).generateInitForCPNSpecPkg(prod) @@ -298,7 +298,7 @@ class ProductGenerator extends AbstractGenerator { System.out.println(" > act: " + SnakesHelper.action(a, func)) actTxt += ''' - «SnakesHelper.action(a, func)» + «Utils.surroundWithTryCatch(a,0,SnakesHelper.action(a, func))» ''' } } @@ -477,7 +477,7 @@ class ProductGenerator extends AbstractGenerator { def generateOnlineMBTController(Product envModel, Product sutModel, IFileSystemAccess2 fsa, IGeneratorContext context) { - (new Utils()).generateOnlineMBTController(envModel, sutModel, fsa, context) + Utils.generateOnlineMBTController(envModel, sutModel, fsa, context) } static def Integer intValue(ExpressionConstantInt expr) { diff --git a/bundles/nl.asml.matala.product/src/nl/asml/matala/product/generator/Utils.xtend b/bundles/nl.asml.matala.product/src/nl/asml/matala/product/generator/Utils.xtend index 33aed49c..42ee785d 100644 --- a/bundles/nl.asml.matala.product/src/nl/asml/matala/product/generator/Utils.xtend +++ b/bundles/nl.asml.matala.product/src/nl/asml/matala/product/generator/Utils.xtend @@ -15,6 +15,7 @@ package nl.asml.matala.product.generator import java.util.ArrayList import java.util.HashMap import java.util.LinkedHashSet +import java.util.List import java.util.Set import nl.asml.matala.product.product.Block import nl.asml.matala.product.product.Blocks @@ -28,9 +29,9 @@ import nl.asml.matala.product.product.SymbConstraint import nl.asml.matala.product.product.Update import nl.asml.matala.product.product.UpdateOutVar import nl.asml.matala.product.product.VarRef +import nl.esi.comma.assertthat.assertThat.DataAssertions import nl.esi.xtext.actions.actions.AssignmentAction import nl.esi.xtext.actions.actions.RecordFieldAssignmentAction -import nl.esi.comma.assertthat.assertThat.DataAssertions import nl.esi.xtext.expressions.expression.ExpressionAddition import nl.esi.xtext.expressions.expression.ExpressionAnd import nl.esi.xtext.expressions.expression.ExpressionAny @@ -66,13 +67,17 @@ import nl.esi.xtext.expressions.expression.ExpressionVariable import nl.esi.xtext.expressions.expression.ExpressionVector import nl.esi.xtext.expressions.expression.Field import nl.esi.xtext.expressions.expression.Variable +import org.eclipse.emf.ecore.EObject import org.eclipse.xtext.generator.IFileSystemAccess2 import org.eclipse.xtext.generator.IGeneratorContext +import org.eclipse.xtext.nodemodel.util.NodeModelUtils import static nl.esi.xtext.common.lang.utilities.EcoreUtil3.serialize class Utils { + static val INDENT = 4 + // Added for Asserts dispatch def String printConstraint(DataAssertions ref) { return printConstraint(ref.eContainer as Update) + "." + ref.name @@ -339,7 +344,7 @@ class Utils } // The Python Test Scenario Generator Class - def generateTestSCNTxt(String name, Product prod, String pSpecFile) { + static def generateTestSCNTxt(String name, Product prod, String pSpecFile) { return ''' import json @@ -366,12 +371,13 @@ class Utils constraint_dict = {} tr_assert_ref_dict = {} - def __init__(self, _mapTrAssert, _constraint_dict, _tr_assert_ref_dict): + def __init__(self, _pspec_path, _mapTrAssert, _constraint_dict, _tr_assert_ref_dict): self.step_list = [] self.step_dependencies = [] self.map_transition_assert = _mapTrAssert self.constraint_dict = _constraint_dict self.tr_assert_ref_dict = _tr_assert_ref_dict + self.pspec_path = _pspec_path def generate_viz(self, idx, output_dir): txt = "@startuml\n" @@ -386,12 +392,12 @@ class Utils # txt += "%s" % elm.payload # txt += "\nend note\n" txt += "@enduml" - + fname = output_dir / f"scenario{str(idx)}.plantuml" os.makedirs(os.path.dirname(fname), exist_ok=True) with open(fname, 'w') as f: f.write(txt) - + # Deprecated. To be Removed. DB 03.04.2025 def recurseJson(self, items, prefix): txt = "" @@ -417,7 +423,7 @@ class Utils raise TypeError('Unsupported type') txt += f" {prefix} := {items}\n" return txt - + def printData(self, idata): txt = "" for k, v in idata.items(): @@ -427,10 +433,10 @@ class Utils # for jk in j.keys(): # txt += self.recurseJson(j[jk], "%s.%s" % (k,jk)) return txt - + def generateTSpec(self, idx, sutTypesList, sutVarTransitionMap, transitionQnameMap, output_dir): txt = "" - txt += "import \"«pSpecFile»\"\n\n" + txt += f"""import "{self.pspec_path}«pSpecFile»"\n\n""" «(new Utils()).usageList(prod)» txt += "\nabstract-test-definition\n\n" txt += "Test-Scenario: S%s\n" % idx @@ -564,22 +570,22 @@ class Utils # print("%s" % elm.step_name) # print("%s" % elm.depends_on) # print("%s" % elm.payload) - - + + class Step: step_name = "" input_data = {} output_data = {} output_suppress = [] is_assert = False - + def __init__(self, _is_assert): self.step_name = "" self.input_data = {} self.output_data = {} self.output_suppress = [] self.is_assert = _is_assert - + def compare(self, _step, mapTrAssert): step_dep = StepDependency() isMatched = False @@ -610,45 +616,45 @@ class Utils return step_dep else: return None - - + + class StepDependency: step_name = "" depends_on = "" var_ref = [] payload = "" - + def __init__(self): self.step_name = "" self.depends_on = "" self.var_ref = [] self.payload = "" - - + + class Constraint: var_ref = "" dir = "" centry = [] - + def __init__(self, v, d, ce): self.var_ref = v self.dir = d self.centry = ce - - + + class CEntry: name = "" constr = "" - + + def __init__(self, n, c): self.name = n self.constr = c - ''' } - def toTypes(String class_name, ArrayList import_list, HashMap var_decl_map) { + static def toTypes(String class_name, ArrayList import_list, HashMap var_decl_map) { ''' class Types: def __init__(self): @@ -657,14 +663,17 @@ class Utils ''' } - def getDataContainerClass(String dataGetterTxt, String methodTxt) + static def getDataContainerClass(String prod_name, String dataGetterTxt, String methodTxt) { // var data_container_class = return ''' import copy import json - + if __package__ is None or __package__ == '': + from «prod_name»_reporting import get_reporting, Location + else: + from .«prod_name»_reporting import get_reporting, Location class Data: @@ -685,7 +694,7 @@ class Utils } - def generateOnlineMBTController(Product envModel, Product sutModel, + static def generateOnlineMBTController(Product envModel, Product sutModel, IFileSystemAccess2 fsa, IGeneratorContext context ) { var txt = @@ -795,6 +804,231 @@ class Utils fsa.generateFile('OnlineMBT_Controller.py', txt) } + + static def getReportingClass(String name) + { + return + ''' + import json + import traceback + from enum import Enum + from typing import List, Optional, Dict, Any + from dataclasses import dataclass, field + from pathlib import Path + + class StatusException(Exception): + def __init__(self, message: str): + super().__init__(message) + + class Severity(Enum): + OK = 0 + INFO = 1 + WARNING = 2 + ERROR = 3 + CANCEL = 4 + + @dataclass + class Location: + startLine: int + endLine: int + offset: int + length: int + text: str + + def to_dict(self) -> Dict[str, Any]: + return { + 'startLine': self.startLine, + 'endLine': self.endLine, + 'offset': self.offset, + 'length': self.length, + 'text': self.text, + } + + @dataclass + class StatusReport: + plugin: str + severity: Severity + message: str + source: str = "" + code: int = 0 + details: Optional[str] = None + location: Optional[Location] = None + children: List['StatusReport'] = field(default_factory=list) + exception: Optional[Exception] = field(default=None, repr=False) + + def __post_init__(self): + if self.exception is not None: + if self.details is None: + self.details = self._get_stack_trace_as_string(self.exception) + self.exception = None # Don't retain non-serializable object + + if self.children: + child_severities = [child.severity for child in self.children if child is not None] + if child_severities: + max_child_severity = max(child_severities, key=lambda s: s.value) + if max_child_severity.value > self.severity.value: + self.severity = max_child_severity + + @staticmethod + def _get_stack_trace_as_string(exception: Exception) -> str: + if exception is None: + return None + tb_lines = traceback.format_exception(type(exception), exception, exception.__traceback__) + if len(tb_lines) > 15: + tb_lines = tb_lines[:15] + [f"\t... {len(tb_lines) - 15} more\n"] + return "".join(tb_lines) + + def to_dict(self) -> Dict[str, Any]: + return { + 'plugin': self.plugin, + 'severity': self.severity.name, + 'message': self.message, + 'source': self.source, + 'code': self.code, + 'details': self.details, + 'location': self.location.to_dict() if self.location else None, + 'children': [child.to_dict() for child in self.children if child is not None], + } + + class StatusReporting: + def __init__(self, save_path: str): + self.save_path = Path(save_path) + self.reports: List[StatusReport] = [] + + def _log(self, severity: Severity, message: str, source: str = "", code: int = 0, + details: Optional[str] = None, exception: Optional[Exception] = None, location: Optional[Location] = None) -> StatusReport: + report = StatusReport( + plugin="", + severity=severity, + message=message, + source=source, + code=code, + details=details, + location=location, + exception=exception + ) + self.reports.append(report) + return report + + def info(self, message: str, source: str = "", code: int = 0, details: Optional[str] = None, location: Location = None) -> StatusReport: + return self._log(Severity.INFO, message, source, code, details, None, location) + + def warning(self, message: str, source: str = "", code: int = 0, details: Optional[str] = None, location: Location = None) -> StatusReport: + return self._log(Severity.WARNING, message, source, code, details, None, location) + + def error(self, message: str, source: str = "", code: int = 0, + details: Optional[str] = None, location: Location = None) -> StatusReport: + return self._log(Severity.ERROR, message, source, code, details, None, location) + + def exception(self, message: str, exception: Exception, source: str = "", details: str = None, code: int = 0, location: Location = None) -> StatusReport: + self._log(Severity.ERROR, message, source, code, details, exception, location) + #on exception the process is stopped + raise StatusException(message) + + def save(self) -> Severity: + + root_severity = Severity.OK + if self.reports: + root_severity = max((report.severity for report in self.reports), key=lambda s: s.value) + + root_report = StatusReport( + plugin="", + severity=root_severity, + message=f"Python generation of «name»", + source="", + code=0, + details=None, + location=None, + children=self.reports, + exception=None + ) + + data = root_report.to_dict() + with open(self.save_path, 'w') as f: + json.dump(data, f, indent=2) + + return root_severity + + + _status_reporting_instance: Optional[StatusReporting] = None + + def initialize_reporting(save_path: str) -> StatusReporting: + global _status_reporting_instance + _status_reporting_instance = StatusReporting(save_path) + return _status_reporting_instance + + def get_reporting() -> StatusReporting: + global _status_reporting_instance + if _status_reporting_instance is None: + raise RuntimeError("StatusReporting not initialized. Call initialize_reporting() first.") + return _status_reporting_instance + ''' + } + + + static def String surroundWithTryCatch(EObject ref, int depth, String txt) { + var indent = " ".repeat(depth * INDENT) + var nextIndent = " ".repeat((depth + 1) * INDENT) + var sourceLocation = getSourceLocation(ref).replace("\n", "\n" + nextIndent) + var body = txt.trim().replace("\n", "\n" + nextIndent) + + var result = String.join("\n", + indent + "try:", + nextIndent + body, + indent + "except Exception as e:", + nextIndent + sourceLocation, + nextIndent + "get_reporting().exception(str(e), e, details=__location.text, source=__source_file, location=__location)", + "" + ) + return result + } + + static def String getSourceLocation(EObject action) { + var List result = new ArrayList() + + var node = NodeModelUtils.getNode(action) + + if (node !== null) { + var text = node.getText() + // Escape for Python and limit to 50 chars + text = escapeAndLimitText(text, 500) + var locationStr = "__location = Location(" + node.getStartLine() + "," + node.getEndLine() + "," + + node.getOffset() + "," + node.getLength() + ",\"" + text + "\")" + result.add(locationStr) + } + if (action.eResource() !== null) { + result.add("__source_file = \"" + action.eResource().getURI().lastSegment() +'"') + } + + // Try to get the line number from the ILocationData if available + // This depends on your setup - you may need to adjust based on your EMF configuration + + return String.join("\n", result) + } + + static def String escapeAndLimitText(String text, int limit) { + if (text === null) { + return "" + } + + // Escape special characters for Python + var escaped = text.trim() + .replaceAll("\\s+", " ") + .replace("\\", "\\\\") + .replace("\"", "\\\"") + .replace("\n", "") + .replace("\r", "") + .replace("\t", " ") + + // Limit to specified length with "..." suffix if truncated + if (escaped.length() > limit) { + escaped = escaped.substring(0, limit - 3) + "..." + } + + return escaped + } + + // /* TODO Is this deprecated? Who is using this? Commented DB 16.03.2025 */ // def Map recurseTypes(Type typ) { // var constructors = newLinkedHashMap() @@ -815,4 +1049,5 @@ class Utils // } // return constructors // } + } \ No newline at end of file diff --git a/bundles/nl.esi.comma.project.standard.cli/META-INF/MANIFEST.MF b/bundles/nl.esi.comma.project.standard.cli/META-INF/MANIFEST.MF index a5c3a3fb..87e693dc 100644 --- a/bundles/nl.esi.comma.project.standard.cli/META-INF/MANIFEST.MF +++ b/bundles/nl.esi.comma.project.standard.cli/META-INF/MANIFEST.MF @@ -5,6 +5,8 @@ Bundle-SymbolicName: nl.esi.comma.project.standard.cli Bundle-Vendor: TNO-ESI Bundle-Version: 4.2.0.qualifier Export-Package: nl.esi.comma.project.standard.cli +Import-Package: io.github.classgraph;version="[4.8.0,5.0.0)", + org.aopalliance.intercept;version="1.0.0" Require-Bundle: nl.esi.comma.project.standard;visibility:=reexport, com.google.inject, org.eclipse.xtext.ide, diff --git a/bundles/nl.esi.comma.project.standard.cli/dist/.vscode/launch.json b/bundles/nl.esi.comma.project.standard.cli/dist/.vscode/launch.json index db150ecc..1111034d 100644 --- a/bundles/nl.esi.comma.project.standard.cli/dist/.vscode/launch.json +++ b/bundles/nl.esi.comma.project.standard.cli/dist/.vscode/launch.json @@ -8,7 +8,7 @@ "request": "launch", "program": "server/CPNServer.py", "console": "integratedTerminal", - "args": ["--web-path", "/bpmn4s-editor/bpmn4s-editor/public", "--server-path", "${workspaceFolder}/../target/dist/server", "--debug"], + "args": ["--web-path", "/bpmn4s-editor/bpmn4s-editor/public", "--server-path", "${workspaceFolder}/../target/dist/server", "--repository-path", "${workspaceFolder}/../target/dist/models", "--debug"], "cwd": "${workspaceFolder}" } , diff --git a/bundles/nl.esi.comma.project.standard.cli/dist/server/CPNServer.py b/bundles/nl.esi.comma.project.standard.cli/dist/server/CPNServer.py index bb78fc78..c522d6b2 100644 --- a/bundles/nl.esi.comma.project.standard.cli/dist/server/CPNServer.py +++ b/bundles/nl.esi.comma.project.standard.cli/dist/server/CPNServer.py @@ -77,6 +77,7 @@ def format(self, record): BPMN4S_GEN = os.path.join(SERVER_PATH, BPMN4S_JAR_NAME) JAVA_REL_PATH = ("jre", "bin", "java.exe") JAVA_PATH = os.path.join(SERVER_PATH, *JAVA_REL_PATH) +JAVA_DEBUG_PORT_LSP = 4000 SYS_TEMP = tempfile.gettempdir() BPMN4S_TEMP = os.path.join(SYS_TEMP,'bpmn4s') @@ -130,6 +131,7 @@ async def lifespan(app: FastAPI): allow_credentials=True, allow_methods=["*"], allow_headers=["*"], + expose_headers=["Content-Disposition"], ) def build_and_load_model(model_path:str): @@ -199,21 +201,29 @@ def generate_tests( model_path:str, num_tests:int=1, depth_limit:int=500, state_ logger.debug("generate_tests stdout: %s", result.stdout.decode('utf-8', errors='replace').rstrip()) if result.stderr: logger.debug("generate_tests stderr: %s", result.stderr.decode('utf-8', errors='replace').rstrip()) - if result.returncode != 0: - raise utils.BPMN4SException( - cliargs={ - 'bpmn-file': model_name, - 'num-tests': num_tests, - 'depth-limit': depth_limit, - 'state-limit': state_limit - }, - result=result - ) + cli_args= { + 'bpmn-file': model_name, + 'num-tests': num_tests, + 'depth-limit': depth_limit, + 'state-limit': state_limit, + } + # zip filename (without .zip extension) zip_filename = os.path.join(model_dir,model_name) + # path to root folder + root_dir = os.path.join(model_dir,'src-gen') # path to directory about to be zipped - output_dir = os.path.join(model_dir,'src-gen',taskname) + output_dir = os.path.join(root_dir,taskname) + os.makedirs(output_dir, exist_ok=True) + # the backend generates a report folder in the root_dir (doesn't know taskname), we need to move it to the output_dir + report_path = os.path.join(output_dir, 'report') + os.rename(os.path.join(root_dir,'report'), report_path) + # store results in the report dir + utils.store_results(report_path, result, cli_args) + + write_status_report_html(output_dir, report_path) + # store bpmn and prj files in bpmn directory bpmn_dir = os.path.join(output_dir,'bpmn') os.makedirs(bpmn_dir, exist_ok=True) @@ -228,6 +238,29 @@ def generate_tests( model_path:str, num_tests:int=1, depth_limit:int=500, state_ logger.error(f"An error occurred while deleting generated test: {str(e)}", file=sys.stderr) return zip_filename, result +def write_status_report_html(output_dir, report_path): + """Write a self-contained status report HTML file to the output directory. + + Reads the `status_report.html` template from `WEB_PATH` and embeds the + contents of `StatusReport.json` from `report_path` into it. The generated + file is fully self-contained, so it can be opened directly from the zip + archive without cross-origin or path issues. + + Silently logs a warning if the HTML file cannot be written, but does not raise an exception. + """ + try: + status_report_html = os.path.join(WEB_PATH, "status_report.html") + #read as string + with open(status_report_html, "r") as html_file: + status_report_html_str = html_file.read() + with open(os.path.join(report_path, "StatusReport.json"), "r") as status_report_json: + status_report_json_str = status_report_json.read() + status_report_html_str = status_report_html_str.replace("!__STATUS_REPORT_JSON__!", status_report_json_str) + with open(os.path.join(output_dir, "status_report.html"), "w") as output_html_file: + output_html_file.write(status_report_html_str) + except Exception as e: + logger.warning("Could not write status report HTML") + # The endpoint of our FastAPI app @app.post("/BPMNParser") async def handle_bpmn(bpmn_file: UploadFile = File(alias="bpmn-file")): @@ -639,6 +672,17 @@ def find_free_port() -> Optional[int]: logger.error(f"Failed to find free port: {e}") return None + def ensure_port_available(port: int, purpose: str) -> bool: + """Return whether a fixed port needed for debugging is available.""" + try: + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.bind(("127.0.0.1", port)) + s.close() + return True + except OSError: + logger.warning(f"Port {port} is not available for {purpose}; continuing without Java debugging.") + return False + lsp_port = find_free_port() if lsp_port is None: logger.error("Failed to find an available port for LSP subprocess. Please check your system resources.") @@ -657,6 +701,15 @@ def find_free_port() -> Optional[int]: # Start Java ServerLauncher which runs both LSP and REST servers lsp_command = [ JAVA_PATH, + ] + + if args.debug and ensure_port_available(JAVA_DEBUG_PORT_LSP, "the Java LSP debug agent"): + lsp_command.append( + f"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=127.0.0.1:{JAVA_DEBUG_PORT_LSP}" + ) + logger.info(f"Java debug agent listening on 127.0.0.1:{JAVA_DEBUG_PORT_LSP}") + + lsp_command.extend([ "-cp", BPMN4S_GEN, "nl.asml.matala.server.ServerLauncher", @@ -666,7 +719,7 @@ def find_free_port() -> Optional[int]: str(REST_PORT), "--repository-path", REPOSITORY_PATH_ARG, - ] + ]) logger.debug(f"LSP command: {' '.join(lsp_command)}") logger.debug(f"Using JAVA_PATH: {JAVA_PATH}") diff --git a/bundles/nl.esi.comma.project.standard.cli/dist/server/CPNUtils.py b/bundles/nl.esi.comma.project.standard.cli/dist/server/CPNUtils.py index 13ff927f..96d4dd98 100644 --- a/bundles/nl.esi.comma.project.standard.cli/dist/server/CPNUtils.py +++ b/bundles/nl.esi.comma.project.standard.cli/dist/server/CPNUtils.py @@ -11,6 +11,8 @@ # SPDX-License-Identifier: MIT # +import json +import os import re from subprocess import CompletedProcess import typing, types @@ -18,10 +20,21 @@ import importlib.util import glob import datetime +from dataclasses import dataclass +from dataclasses_json import dataclass_json from abc import ABC, abstractmethod from threading import Lock +@dataclass_json +@dataclass +class BPMN4SResult(): + cliargs: dict + returncode: int + stdout: str + stderr: str + + class BPMN4SException(Exception): def __init__(self,cliargs:dict, result: CompletedProcess[bytes], *args): super().__init__(*args) @@ -31,6 +44,23 @@ def __init__(self,cliargs:dict, result: CompletedProcess[bytes], *args): self.stderr = result.stderr.decode('utf-8').replace('\r\n','\n') self.returncode = result.returncode +def store_results( output_dir: str, result : CompletedProcess[bytes], cli_args: dict): + process={ + 'args': cli_args, + 'result': { + 'return-code': result.returncode + } + } + result_stdout_path = os.path.join(output_dir, 'stdout.txt') + with open(result_stdout_path, "w") as file: + file.write(result.stdout.decode('utf-8').replace('\r\n','\n')) + result_stderr_path = os.path.join(output_dir, 'stderr.txt') + with open(result_stderr_path, "w") as file: + file.write(result.stderr.decode('utf-8').replace('\r\n','\n')) + result_process_path = os.path.join(output_dir, 'process.json') + with open(result_process_path, "w") as file: + file.write(json.dumps(process, indent=4)) + class AbstractCPNControl(ABC): diff --git a/bundles/nl.esi.comma.project.standard.cli/dist/server/requirements.txt b/bundles/nl.esi.comma.project.standard.cli/dist/server/requirements.txt index 6c01778c..1fd46845 100644 --- a/bundles/nl.esi.comma.project.standard.cli/dist/server/requirements.txt +++ b/bundles/nl.esi.comma.project.standard.cli/dist/server/requirements.txt @@ -4,4 +4,5 @@ fastapi uvicorn[standard] websockets python-multipart -httpx \ No newline at end of file +httpx +dataclasses_json \ No newline at end of file diff --git a/bundles/nl.esi.comma.project.standard.ui/src/nl/esi/comma/project/standard/ui/StandardProjectUiModule.xtend b/bundles/nl.esi.comma.project.standard.ui/src/nl/esi/comma/project/standard/ui/StandardProjectUiModule.xtend index bc6b112b..f6cec7a7 100644 --- a/bundles/nl.esi.comma.project.standard.ui/src/nl/esi/comma/project/standard/ui/StandardProjectUiModule.xtend +++ b/bundles/nl.esi.comma.project.standard.ui/src/nl/esi/comma/project/standard/ui/StandardProjectUiModule.xtend @@ -15,22 +15,41 @@ */ package nl.esi.comma.project.standard.ui +import nl.esi.xtext.common.lang.reporting.IStatusReporting +import nl.esi.xtext.common.lang.reporting.StatusReportingEclipseRuntime import nl.esi.xtext.types.ui.contentassist.XPlusHyperLinkDetector import org.eclipse.core.runtime.Platform import org.eclipse.jface.text.hyperlink.IHyperlinkDetector -import org.eclipse.ui.plugin.AbstractUIPlugin +import com.google.inject.Provides +import org.eclipse.core.runtime.Plugin +import nl.esi.comma.project.standard.ui.internal.StandardActivator /** * Use this class to register components to be used within the Eclipse IDE. */ class StandardProjectUiModule extends AbstractStandardProjectUiModule { - new(AbstractUIPlugin plugin) { + + final StandardActivator plugin + + new(StandardActivator plugin) { super(plugin) + this.plugin = plugin Platform.getBundle("org.eclipse.debug.ui").start } override Class bindIHyperlinkDetector() { return XPlusHyperLinkDetector } + + @Provides + def Plugin providePlugin() { + return this.plugin; + } + + def Class bindIStatusReporter() { + return StatusReportingEclipseRuntime + } + + } diff --git a/bundles/nl.esi.comma.project.standard/src/nl/esi/comma/project/standard/StandardProjectRuntimeModule.xtend b/bundles/nl.esi.comma.project.standard/src/nl/esi/comma/project/standard/StandardProjectRuntimeModule.xtend index 9c9d0df1..4d1bf9fc 100644 --- a/bundles/nl.esi.comma.project.standard/src/nl/esi/comma/project/standard/StandardProjectRuntimeModule.xtend +++ b/bundles/nl.esi.comma.project.standard/src/nl/esi/comma/project/standard/StandardProjectRuntimeModule.xtend @@ -21,6 +21,8 @@ import nl.esi.xtext.expressions.functions.ExpressionFunctionLibrariesProvider import nl.esi.xtext.expressions.functions.IExpressionFunctionLibrariesProvider import nl.esi.xtext.expressions.scoping.ExpressionsImportUriGlobalScopeProvider import org.eclipse.xtext.scoping.IGlobalScopeProvider +import nl.esi.xtext.common.lang.reporting.StatusReportCollector +import nl.esi.xtext.common.lang.reporting.IStatusReporting /** * Use this class to register components to be used at runtime / without the Equinox extension registry. @@ -39,4 +41,8 @@ class StandardProjectRuntimeModule extends AbstractStandardProjectRuntimeModule return ExpressionConvertersProvider } + def Class bindIStatusReporter() { + return StatusReportCollector + } + } diff --git a/bundles/nl.esi.comma.project.standard/src/nl/esi/comma/project/standard/generator/PetriNetToAbstractTspecGenerator.xtend b/bundles/nl.esi.comma.project.standard/src/nl/esi/comma/project/standard/generator/PetriNetToAbstractTspecGenerator.xtend index b8eee822..65cb3a1d 100644 --- a/bundles/nl.esi.comma.project.standard/src/nl/esi/comma/project/standard/generator/PetriNetToAbstractTspecGenerator.xtend +++ b/bundles/nl.esi.comma.project.standard/src/nl/esi/comma/project/standard/generator/PetriNetToAbstractTspecGenerator.xtend @@ -14,7 +14,12 @@ package nl.esi.comma.project.standard.generator import java.io.BufferedReader import java.io.PrintStream +import java.nio.file.Files +import java.nio.file.Path import java.util.concurrent.TimeUnit +import nl.esi.xtext.common.lang.reporting.IStatusReporting +import nl.esi.xtext.common.lang.reporting.Severity +import nl.esi.xtext.common.lang.reporting.StatusReportHelper import org.eclipse.emf.common.util.URI import org.eclipse.emf.ecore.resource.Resource import org.eclipse.emf.ecore.resource.ResourceSet @@ -24,16 +29,16 @@ import org.eclipse.xtext.generator.IGeneratorContext import static extension nl.esi.xtext.common.lang.generator.FileSystemAccessUtil.* import static extension nl.esi.xtext.common.lang.utilities.EcoreUtil3.* +import static extension nl.esi.comma.project.standard.generator.^extension.IStandardProjectGeneratorExtension.FOLDER_PSPEC class PetriNetToAbstractTspecGenerator extends AbstractGenerator { + + val IStatusReporting reporting; val String pythonExe; - new() { - this(null) - } - - new(String pythonExe) { + new(String pythonExe, IStatusReporting reporting) { this.pythonExe = pythonExe ?: 'python.exe' + this.reporting = reporting } override doGenerate(Resource res, IFileSystemAccess2 fsa, IGeneratorContext ctx) { @@ -41,19 +46,25 @@ class PetriNetToAbstractTspecGenerator extends AbstractGenerator { } def void doGenerate(ResourceSet rst, URI uri, IFileSystemAccess2 fsa, IGeneratorContext ctx) { + val statusReportFile = fsa.rootURI.appendSegment("status_report.json").toPath val process = Runtime.getRuntime().exec(#[ pythonExe, uri.toPath, '-no_sim=TRUE', '-tsdir=' + fsa.rootURI.toPath, - '-pudir=' + fsa.getURI('plantuml').toPath + '-pudir=' + fsa.getURI('plantuml').toPath, + '-srfile=' + statusReportFile, + '-pspath=' + '../'+ FOLDER_PSPEC+'/' ]) process.inputReader.pipeTo(System.out) process.errorReader.pipeTo(System.err) if (!process.waitFor(10, TimeUnit::MINUTES)) { process.destroyForcibly throw new RuntimeException('Python process did not end in time') - } else if (process.exitValue != 0) { + } + val report = StatusReportHelper.fromJson(Files.readString(Path.of(statusReportFile))) + reporting.addReport(report) + if (Severity.fromValue(process.exitValue).isError) { throw new RuntimeException( '''Python process exited with exit code «process.exitValue», see error output for details.''') } diff --git a/bundles/nl.esi.comma.project.standard/src/nl/esi/comma/project/standard/generator/StandardProjectGenerator.xtend b/bundles/nl.esi.comma.project.standard/src/nl/esi/comma/project/standard/generator/StandardProjectGenerator.xtend index 7712cf21..4e6cf1ab 100644 --- a/bundles/nl.esi.comma.project.standard/src/nl/esi/comma/project/standard/generator/StandardProjectGenerator.xtend +++ b/bundles/nl.esi.comma.project.standard/src/nl/esi/comma/project/standard/generator/StandardProjectGenerator.xtend @@ -27,14 +27,17 @@ import nl.esi.comma.project.standard.standardProject.OfflineGenerationTarget import nl.esi.comma.project.standard.standardProject.Project import nl.esi.comma.project.standard.standardProject.TargetConfig import nl.esi.comma.testspecification.generator.utils.MergeConcreteDataAssigments -import nl.esi.xtext.common.lang.base.Import +import nl.esi.xtext.common.lang.reporting.IStatusReporting +import nl.esi.xtext.common.lang.reporting.StatusReportHelper +import nl.esi.xtext.common.lang.utilities.EcoreUtil3 import org.eclipse.emf.ecore.resource.Resource import org.eclipse.emf.ecore.resource.ResourceSet import org.eclipse.xtext.generator.AbstractGenerator import org.eclipse.xtext.generator.IFileSystemAccess2 import org.eclipse.xtext.generator.IGeneratorContext -import static nl.esi.comma.project.standard.generator.^extension.IStandardProjectGeneratorExtension.*; +import static nl.esi.comma.project.standard.generator.^extension.IStandardProjectGeneratorExtension.* + import static extension nl.esi.xtext.common.lang.generator.FileSystemAccessUtil.* import static extension nl.esi.xtext.common.lang.utilities.EcoreUtil3.* import static extension org.eclipse.emf.ecore.util.EcoreUtil.* @@ -49,6 +52,9 @@ class StandardProjectGenerator extends AbstractGenerator { @Inject IStandardProjectGeneratorExtension.Registry generatorExtensions; + @Inject + IStatusReporting reporting; + override doGenerate(Resource res, IFileSystemAccess2 fsa, IGeneratorContext ctx) { for (project : res.contents.filter(Project)) { for (task : project.offlineBlocks) { @@ -83,9 +89,11 @@ class StandardProjectGenerator extends AbstractGenerator { throw new Exception('No product found in resource: ' + productURI) } productRes.resolveAll() - product.imports.forEach[productRes.getResource(importURI).validate()] - productRes.validate() - + //validate but stop on the first error + var error = product.imports.map[productRes.getResource(importURI).validate].findFirst[it]!==null + if (error || productRes.validate){ + return + } // PspecToPetriNetGenerator // Generate CPNServer (a.k.a. abstract Tspec generator) and Petri-nets (new ProductGenerator).doGenerate(productRes, fsa, ctx) @@ -98,44 +106,42 @@ class StandardProjectGenerator extends AbstractGenerator { val specName = product.specification.name val petriNetURI = fsa.getURI('''«FOLDER_CPN_SERVER»/«specName»/«specName».py''') val absTspecFsa = fsa.createFolderAccess(FOLDER_ABSTRACT_TSPEC) - (new PetriNetToAbstractTspecGenerator(task.pythonExe)).doGenerate(rst, petriNetURI, absTspecFsa, ctx) + (new PetriNetToAbstractTspecGenerator(task.pythonExe, reporting)).doGenerate(rst, petriNetURI, absTspecFsa, ctx) for (absTspecFileName : absTspecFsa.list(ROOT_PATH).filter[endsWith('.atspec')]) { val tspecName = absTspecFileName.replaceAll('\\.atspec$', '') val absTspecRes = absTspecFsa.loadResource(absTspecFileName, rst) - // Fix the pspec import - val productImportURI = productURI.deresolve(absTspecRes.URI) - absTspecRes.allContents.filter(Import).filter[importURI == productURI.lastSegment].forEach [ - importURI = productImportURI.toString - ] - absTspecRes.save(null) - // Validate the generated abstract tspec - absTspecRes.validate() - - // Generate concrete tspec - val conTspecFsa = fsa.createFolderAccess(FOLDER_CONCRETE_TSPEC + '/' + tspecName) - val fromAbstractToConcreteGen = new FromAbstractToConcrete() - fromAbstractToConcreteGen.doGenerate(absTspecRes, conTspecFsa, ctx) - - val conTspecFileName = tspecName + '.tspec' - val conTspecRes = conTspecFsa.loadResource(conTspecFileName, rst) - MergeConcreteDataAssigments.transform(conTspecRes) - conTspecRes.save(null) - conTspecRes.validate() - - // TODO fetch these FAST configuration parameters from somewhere else (e.g., .prj task) - val renamingRules = task.renamingRules !== null ? createPropertiesMap(task.renamingRules) : new HashMap - val genParams = task.generatorParams !== null ? createPropertiesMap(task.generatorParams) : new HashMap - // TODO fetch this from somewhere else - genParams.putIfAbsent('prefixPath', './vfab2_scenario/FAST/testcases/' + specName + '_' + tspecName + '/') - - val extensionContext = new StandardProjectGeneratorContext(ctx?.cancelIndicator, renamingRules, genParams) - generatorExtensions.forEach[doGenerate(conTspecRes, fsa, extensionContext)] + // Validate the generated abstract tspec, stop this transformation on error + val absTspecValid = !absTspecRes.validate + if (absTspecValid) { + // Generate concrete tspec + val conTspecFsa = fsa.createFolderAccess(FOLDER_CONCRETE_TSPEC + '/' + tspecName) + val fromAbstractToConcreteGen = new FromAbstractToConcrete() + fromAbstractToConcreteGen.doGenerate(absTspecRes, conTspecFsa, ctx) + + val conTspecFileName = tspecName + '.tspec' + val conTspecRes = conTspecFsa.loadResource(conTspecFileName, rst) + + MergeConcreteDataAssigments.transform(conTspecRes) + val conTspecValid = !conTspecRes.validate + trySave(conTspecRes) + // Validate the generated conctete tspec, stop this transformation on error + if (conTspecValid){ + // TODO fetch these FAST configuration parameters from somewhere else (e.g., .prj task) + val renamingRules = task.renamingRules !== null ? createPropertiesMap(task.renamingRules) : new HashMap + val genParams = task.generatorParams !== null ? createPropertiesMap(task.generatorParams) : new HashMap + // TODO fetch this from somewhere else + genParams.putIfAbsent('prefixPath', './vfab2_scenario/FAST/testcases/' + specName + '_' + tspecName + '/') + + val extensionContext = new StandardProjectGeneratorContext(ctx?.cancelIndicator, renamingRules, genParams) + generatorExtensions.forEach[ doGenerate(conTspecRes, fsa, extensionContext)] + } + } } } - def createPropertiesMap(TargetConfig tgtConfig) { + private def createPropertiesMap(TargetConfig tgtConfig) { var props = new HashMap() for (elem : tgtConfig.item) { props.put(elem.key, elem.^val) @@ -143,4 +149,24 @@ class StandardProjectGenerator extends AbstractGenerator { return props } + private def trySave( Resource resource) { + try { + //try to test serialize the file first as it sweeps the file on save + resource.contents.forEach[EcoreUtil3.serialize(it)] + resource.save(null) + } + catch(Exception e) { + reporting.addReport(e) + } + } + /** + * validates the resource + * returns true when error + */ + private def boolean validate(Resource resource) { + val result = StatusReportHelper.validate(resource) + reporting.addReport(result) + return result.error + } } + diff --git a/releng/nl.esi.comma.target/nl.esi.comma.target.target b/releng/nl.esi.comma.target/nl.esi.comma.target.target index 9cbe2f92..45e47bc1 100644 --- a/releng/nl.esi.comma.target/nl.esi.comma.target.target +++ b/releng/nl.esi.comma.target/nl.esi.comma.target.target @@ -95,7 +95,7 @@ - +