forked from sartography/SpiffWorkflow
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathunit_test_extensions.patch
348 lines (331 loc) · 17.9 KB
/
unit_test_extensions.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
diff --git a/SpiffWorkflow/spiff/parser/process.py b/SpiffWorkflow/spiff/parser/process.py
index 4abdb96..2ec536f 100644
--- a/SpiffWorkflow/spiff/parser/process.py
+++ b/SpiffWorkflow/spiff/parser/process.py
@@ -2,9 +2,9 @@ from SpiffWorkflow.dmn.parser.BpmnDmnParser import BpmnDmnParser
from SpiffWorkflow.bpmn.parser.BpmnParser import full_tag
from SpiffWorkflow.bpmn.specs.events import StartEvent, EndEvent, IntermediateThrowEvent, BoundaryEvent, IntermediateCatchEvent
-from SpiffWorkflow.spiff.specs import NoneTask, ManualTask, UserTask, SubWorkflowTask, TransactionSubprocess, CallActivity, ServiceTask
+from SpiffWorkflow.spiff.specs import NoneTask, ManualTask, UserTask, ScriptTask, SubWorkflowTask, TransactionSubprocess, CallActivity, ServiceTask
from SpiffWorkflow.spiff.specs.events.event_types import SendTask, ReceiveTask
-from SpiffWorkflow.spiff.parser.task_spec import SpiffTaskParser, SubWorkflowParser, CallActivityParser, ServiceTaskParser
+from SpiffWorkflow.spiff.parser.task_spec import SpiffTaskParser, SubWorkflowParser, CallActivityParser, ServiceTaskParser, ScriptTaskParser
from SpiffWorkflow.spiff.parser.event_parsers import (SpiffStartEventParser, SpiffEndEventParser, SpiffBoundaryEventParser,
SpiffIntermediateCatchEventParser, SpiffIntermediateThrowEventParser, SpiffSendTaskParser, SpiffReceiveTaskParser)
from SpiffWorkflow.dmn.specs import BusinessRuleTask
@@ -17,6 +17,7 @@ class SpiffBpmnParser(BpmnDmnParser):
full_tag('task'): (SpiffTaskParser, NoneTask),
full_tag('userTask'): (SpiffTaskParser, UserTask),
full_tag('manualTask'): (SpiffTaskParser, ManualTask),
+ full_tag('scriptTask'): (ScriptTaskParser, ScriptTask),
full_tag('subProcess'): (SubWorkflowParser, SubWorkflowTask),
full_tag('transaction'): (SubWorkflowParser, TransactionSubprocess),
full_tag('callActivity'): (CallActivityParser, CallActivity),
diff --git a/SpiffWorkflow/spiff/parser/task_spec.py b/SpiffWorkflow/spiff/parser/task_spec.py
index 32e8ecf..da3961d 100644
--- a/SpiffWorkflow/spiff/parser/task_spec.py
+++ b/SpiffWorkflow/spiff/parser/task_spec.py
@@ -6,6 +6,7 @@ from SpiffWorkflow.bpmn.parser.task_parsers import SubprocessParser
from SpiffWorkflow.bpmn.parser.util import xpath_eval
SPIFFWORKFLOW_MODEL_NS = 'http://spiffworkflow.org/bpmn/schema/1.0/core'
+SPIFFWORKFLOW_MODEL_PREFIX = 'spiffworkflow'
class SpiffTaskParser(TaskParser):
@@ -20,36 +21,55 @@ class SpiffTaskParser(TaskParser):
# Too bad doing this works in such a stupid way.
# We should set a namespace and automatically do this.
extensions = {}
- extra_ns = {'spiffworkflow': SPIFFWORKFLOW_MODEL_NS}
+ extra_ns = {SPIFFWORKFLOW_MODEL_PREFIX: SPIFFWORKFLOW_MODEL_NS}
xpath = xpath_eval(node, extra_ns)
- extension_nodes = xpath('.//bpmn:extensionElements/spiffworkflow:*')
+ extension_nodes = xpath(f'.//bpmn:extensionElements/{SPIFFWORKFLOW_MODEL_PREFIX}:*')
for node in extension_nodes:
name = etree.QName(node).localname
if name == 'properties':
extensions['properties'] = SpiffTaskParser._parse_properties(node)
+ elif name == 'unitTests':
+ extensions['unitTests'] = SpiffTaskParser._parse_script_unit_tests(node)
elif name == 'serviceTaskOperator':
extensions['serviceTaskOperator'] = SpiffTaskParser._parse_servicetask_operator(node)
else:
extensions[name] = node.text
return extensions
- @staticmethod
- def _parse_properties(node):
- extra_ns = {'spiffworkflow': SPIFFWORKFLOW_MODEL_NS}
- xpath = xpath_eval(node, extra_ns)
- property_nodes = xpath('.//spiffworkflow:property')
+ @classmethod
+ def _node_children_by_tag_name(cls, node, tag_name):
+ xpath = cls._spiffworkflow_ready_xpath_for_node(node)
+ return xpath(f'.//{SPIFFWORKFLOW_MODEL_PREFIX}:{tag_name}')
+
+ @classmethod
+ def _parse_properties(cls, node):
+ property_nodes = cls._node_children_by_tag_name(node, 'property')
properties = {}
for prop_node in property_nodes:
properties[prop_node.attrib['name']] = prop_node.attrib['value']
return properties
@staticmethod
- def _parse_servicetask_operator(node):
+ def _spiffworkflow_ready_xpath_for_node(node):
+ extra_ns = {SPIFFWORKFLOW_MODEL_PREFIX: SPIFFWORKFLOW_MODEL_NS}
+ return xpath_eval(node, extra_ns)
+
+ @classmethod
+ def _parse_script_unit_tests(cls, node):
+ unit_test_nodes = cls._node_children_by_tag_name(node, 'unitTest')
+ unit_tests = []
+ for unit_test_node in unit_test_nodes:
+ unit_test_dict = {"id": unit_test_node.attrib['id']}
+ unit_test_dict['inputJson'] = cls._node_children_by_tag_name(unit_test_node, 'inputJson')[0].text
+ unit_test_dict['expectedOutputJson'] = cls._node_children_by_tag_name(unit_test_node, 'expectedOutputJson')[0].text
+ unit_tests.append(unit_test_dict)
+ return unit_tests
+
+ @classmethod
+ def _parse_servicetask_operator(cls, node):
name = node.attrib['id']
result_variable = node.get('resultVariable', None)
- extra_ns = {'spiffworkflow': SPIFFWORKFLOW_MODEL_NS}
- xpath = xpath_eval(node, extra_ns)
- parameter_nodes = xpath('.//spiffworkflow:parameter')
+ parameter_nodes = cls._node_children_by_tag_name(node, 'parameter')
operator = {'name': name, 'resultVariable': result_variable}
parameters = {}
for param_node in parameter_nodes:
@@ -92,6 +112,20 @@ class SubWorkflowParser(SpiffTaskParser):
postscript=postscript)
+class ScriptTaskParser(SpiffTaskParser):
+ def create_task(self):
+ extensions = self.parse_extensions()
+ script = None
+ for child_node in self.node:
+ if child_node.tag.endswith('script'):
+ script = child_node.text
+ # import pdb; pdb.set_trace()
+ return self.spec_class(
+ self.spec, self.get_task_spec_name(), script,
+ lane=self.lane, position=self.position,
+ description=self.node.get('name', None))
+
+
class CallActivityParser(SpiffTaskParser):
def create_task(self):
diff --git a/SpiffWorkflow/spiff/serializer/__init__.py b/SpiffWorkflow/spiff/serializer/__init__.py
index 4ba82d6..364c3eb 100644
--- a/SpiffWorkflow/spiff/serializer/__init__.py
+++ b/SpiffWorkflow/spiff/serializer/__init__.py
@@ -1,4 +1,4 @@
-from .task_spec_converters import NoneTaskConverter, ManualTaskConverter, UserTaskConverter
+from .task_spec_converters import NoneTaskConverter, ManualTaskConverter, UserTaskConverter, ScriptTaskConverter
from .task_spec_converters import TransactionSubprocessConverter, CallActivityTaskConverter, SubWorkflowTaskConverter
from .task_spec_converters import StartEventConverter, EndEventConverter, IntermediateCatchEventConverter, IntermediateThrowEventConverter, \
BoundaryEventConverter, SendTaskConverter, ReceiveTaskConverter, ServiceTaskConverter
diff --git a/SpiffWorkflow/spiff/serializer/task_spec_converters.py b/SpiffWorkflow/spiff/serializer/task_spec_converters.py
index 8c25970..5b24278 100644
--- a/SpiffWorkflow/spiff/serializer/task_spec_converters.py
+++ b/SpiffWorkflow/spiff/serializer/task_spec_converters.py
@@ -2,7 +2,7 @@ from functools import partial
from SpiffWorkflow.bpmn.serializer.bpmn_converters import BpmnTaskSpecConverter
from SpiffWorkflow.bpmn.specs.events import EndEvent, StartEvent, IntermediateThrowEvent, IntermediateCatchEvent, BoundaryEvent
-from SpiffWorkflow.spiff.specs import NoneTask, ManualTask, UserTask, ServiceTask, SubWorkflowTask, TransactionSubprocess, CallActivity
+from SpiffWorkflow.spiff.specs import NoneTask, ManualTask, UserTask, ScriptTask, ServiceTask, SubWorkflowTask, TransactionSubprocess, CallActivity
from SpiffWorkflow.spiff.specs.events import SendTask, ReceiveTask
from SpiffWorkflow.spiff.specs.events.event_definitions import MessageEventDefinition
@@ -35,6 +35,16 @@ class UserTaskConverter(SpiffBpmnTaskConverter):
super().__init__(UserTask, data_converter)
+class ScriptTaskConverter(SpiffBpmnTaskConverter):
+ def __init__(self, data_converter=None):
+ super().__init__(ScriptTask, data_converter)
+
+ def to_dict(self, spec):
+ dct = super().to_dict(spec)
+ dct['script'] = spec.script
+ return dct
+
+
class ServiceTaskConverter(SpiffBpmnTaskConverter):
def __init__(self, data_converter=None):
super().__init__(ServiceTask, data_converter)
diff --git a/SpiffWorkflow/spiff/specs/__init__.py b/SpiffWorkflow/spiff/specs/__init__.py
index 5378a5b..1e18b63 100644
--- a/SpiffWorkflow/spiff/specs/__init__.py
+++ b/SpiffWorkflow/spiff/specs/__init__.py
@@ -2,4 +2,5 @@ from .manual_task import ManualTask
from .none_task import NoneTask
from .subworkflow_task import SubWorkflowTask, TransactionSubprocess, CallActivity
from .user_task import UserTask
+from .script_task import ScriptTask
from .service_task import ServiceTask
diff --git a/SpiffWorkflow/spiff/specs/script_task.py b/SpiffWorkflow/spiff/specs/script_task.py
new file mode 100644
index 0000000..c56e7e8
--- /dev/null
+++ b/SpiffWorkflow/spiff/specs/script_task.py
@@ -0,0 +1,6 @@
+from SpiffWorkflow.spiff.specs.spiff_task import SpiffBpmnTask
+from SpiffWorkflow.bpmn.specs.ScriptTask import ScriptTask as BpmnScriptTask
+
+
+class ScriptTask(BpmnScriptTask, SpiffBpmnTask):
+ pass
diff --git a/tests/SpiffWorkflow/spiff/BaseTestCase.py b/tests/SpiffWorkflow/spiff/BaseTestCase.py
index 92c23eb..248f84a 100644
--- a/tests/SpiffWorkflow/spiff/BaseTestCase.py
+++ b/tests/SpiffWorkflow/spiff/BaseTestCase.py
@@ -3,7 +3,7 @@ import os
from SpiffWorkflow.spiff.parser import SpiffBpmnParser
from SpiffWorkflow.spiff.serializer import NoneTaskConverter, \
- ManualTaskConverter, UserTaskConverter, \
+ ManualTaskConverter, UserTaskConverter, ScriptTaskConverter, \
SubWorkflowTaskConverter, TransactionSubprocessConverter, \
CallActivityTaskConverter, \
StartEventConverter, EndEventConverter, BoundaryEventConverter, \
@@ -16,7 +16,7 @@ from SpiffWorkflow.bpmn.serializer import BpmnWorkflowSerializer
from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase
wf_spec_converter = BpmnWorkflowSerializer.configure_workflow_spec_converter([
- NoneTaskConverter, ManualTaskConverter, UserTaskConverter,
+ NoneTaskConverter, ManualTaskConverter, UserTaskConverter, ScriptTaskConverter,
SubWorkflowTaskConverter, TransactionSubprocessConverter, CallActivityTaskConverter,
StartEventConverter, EndEventConverter, BoundaryEventConverter, SendTaskConverter, ReceiveTaskConverter,
IntermediateCatchEventConverter, IntermediateThrowEventConverter, BusinessRuleTaskConverter,
diff --git a/tests/SpiffWorkflow/spiff/ScriptUnitTestExtensionsTest.py b/tests/SpiffWorkflow/spiff/ScriptUnitTestExtensionsTest.py
new file mode 100644
index 0000000..87c8335
--- /dev/null
+++ b/tests/SpiffWorkflow/spiff/ScriptUnitTestExtensionsTest.py
@@ -0,0 +1,46 @@
+from SpiffWorkflow.task import TaskState
+from .BaseTestCase import BaseTestCase
+from SpiffWorkflow.bpmn.workflow import BpmnWorkflow
+
+# Assure we correctly parse and pass on the Spiffworkflow properties in
+# an extension.
+class ScriptUnitTestExtensionsTest(BaseTestCase):
+
+ def testTask(self):
+ self.task_test()
+
+ def testTaskSaveRestore(self):
+ self.task_test(True)
+
+ def task_test(self, save_restore=False):
+
+ spec, subprocesses = self.load_workflow_spec('script_task_with_unit_tests.bpmn', 'Process_ScriptTaskWithUnitTests')
+ self.workflow = BpmnWorkflow(spec, subprocesses)
+ self.workflow.do_engine_steps()
+ if save_restore:
+ self.save_restore()
+
+ # unitTests should be a list of dicts
+ expected_unit_tests_wrapper_class_name = 'list'
+ expected_unit_test_class_name = 'dict'
+
+ script_with_unit_tests = [t for t in self.workflow.get_tasks() if
+ t.task_spec.name == 'script_with_unit_test_id'][0]
+ print(f"script_with_unit_tests.task_spec.extensions: {script_with_unit_tests.task_spec.extensions}")
+ extensions = script_with_unit_tests.task_spec.extensions
+ unit_test_extensions = extensions['unitTests']
+ print(f"unit_test_extensions: {unit_test_extensions}")
+ print(f"unit_test_extensions.class: {unit_test_extensions.__class__.__name__}")
+ unit_test_extensions_class_name = unit_test_extensions.__class__.__name__
+ self.assertEqual(unit_test_extensions_class_name, expected_unit_tests_wrapper_class_name)
+ self.assertEqual(len(unit_test_extensions), 2)
+ first_unit_test = unit_test_extensions[0]
+ self.assertEqual(first_unit_test.__class__.__name__, expected_unit_test_class_name)
+ expected_first_unit_test = {'id': 'sets_hey_to_true_if_hey_is_false',
+ 'inputJson': '{"hey": false}', 'expectedOutputJson': '{"hey": true}'}
+ self.assertDictEqual(first_unit_test, expected_first_unit_test)
+ # self.assertEqual(len(unit_test_extensions), 2)
+ # self.assertDictEqual({'formJsonSchemaFilename': 'my_json_jschema.json',
+ # 'formUiSchemaFilename': 'my_ui_jschema.json'},
+ # task.task_spec.extensions)
+
diff --git a/tests/SpiffWorkflow/spiff/SpiffPropertiesTest.py b/tests/SpiffWorkflow/spiff/SpiffPropertiesTest.py
index d029f35..9087aae 100644
--- a/tests/SpiffWorkflow/spiff/SpiffPropertiesTest.py
+++ b/tests/SpiffWorkflow/spiff/SpiffPropertiesTest.py
@@ -4,7 +4,7 @@ from SpiffWorkflow.bpmn.workflow import BpmnWorkflow
# Assure we correctly parse and pass on the Spiffworkflow properties in
# an extension.
-class SpiffWorkflowProperties(BaseTestCase):
+class SpiffPropertiesTest(BaseTestCase):
def testTask(self):
self.task_test()
diff --git a/tests/SpiffWorkflow/spiff/data/script_task_with_unit_tests.bpmn b/tests/SpiffWorkflow/spiff/data/script_task_with_unit_tests.bpmn
new file mode 100644
index 0000000..d2873b8
--- /dev/null
+++ b/tests/SpiffWorkflow/spiff/data/script_task_with_unit_tests.bpmn
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_1ny7jp4" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.0.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.17.0">
+ <bpmn:process id="Process_ScriptTaskWithUnitTests" isExecutable="true">
+ <bpmn:startEvent id="StartEvent_1">
+ <bpmn:outgoing>Flow_10jwwqy</bpmn:outgoing>
+ </bpmn:startEvent>
+ <bpmn:sequenceFlow id="Flow_10jwwqy" sourceRef="StartEvent_1" targetRef="Activity_03fldr6" />
+ <bpmn:endEvent id="Event_1qb1u6a">
+ <bpmn:incoming>Flow_0htxke7</bpmn:incoming>
+ </bpmn:endEvent>
+ <bpmn:sequenceFlow id="Flow_0htxke7" sourceRef="script_with_unit_test_id" targetRef="Event_1qb1u6a" />
+ <bpmn:scriptTask id="script_with_unit_test_id" name="Script with unit test">
+ <bpmn:extensionElements>
+ <spiffworkflow:unitTests>
+ <spiffworkflow:unitTest id="sets_hey_to_true_if_hey_is_false">
+ <spiffworkflow:inputJson>{"hey": false}</spiffworkflow:inputJson>
+ <spiffworkflow:expectedOutputJson>{"hey": true}</spiffworkflow:expectedOutputJson>
+ </spiffworkflow:unitTest>
+ <spiffworkflow:unitTest id="sets_something_else_if_no_hey">
+ <spiffworkflow:inputJson>{}</spiffworkflow:inputJson>
+ <spiffworkflow:expectedOutputJson>{"something_else": true}</spiffworkflow:expectedOutputJson>
+ </spiffworkflow:unitTest>
+ </spiffworkflow:unitTests>
+ </bpmn:extensionElements>
+ <bpmn:incoming>Flow_0niwe1y</bpmn:incoming>
+ <bpmn:outgoing>Flow_0htxke7</bpmn:outgoing>
+ <bpmn:script>if 'hey' in locals():
+ hey = True
+else:
+ something_else = True</bpmn:script>
+ </bpmn:scriptTask>
+ <bpmn:sequenceFlow id="Flow_0niwe1y" sourceRef="Activity_03fldr6" targetRef="script_with_unit_test_id" />
+ <bpmn:scriptTask id="Activity_03fldr6" name="Set var">
+ <bpmn:incoming>Flow_10jwwqy</bpmn:incoming>
+ <bpmn:outgoing>Flow_0niwe1y</bpmn:outgoing>
+ <bpmn:script>hey = False</bpmn:script>
+ </bpmn:scriptTask>
+ </bpmn:process>
+ <bpmndi:BPMNDiagram id="BPMNDiagram_1">
+ <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="sample">
+ <bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
+ <dc:Bounds x="132" y="102" width="36" height="36" />
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNShape id="Event_1qb1u6a_di" bpmnElement="Event_1qb1u6a">
+ <dc:Bounds x="642" y="102" width="36" height="36" />
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNShape id="Activity_17ohe7r_di" bpmnElement="script_with_unit_test_id">
+ <dc:Bounds x="440" y="80" width="100" height="80" />
+ <bpmndi:BPMNLabel />
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNShape id="Activity_1fab1y2_di" bpmnElement="Activity_03fldr6">
+ <dc:Bounds x="250" y="80" width="100" height="80" />
+ <bpmndi:BPMNLabel />
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNEdge id="Flow_10jwwqy_di" bpmnElement="Flow_10jwwqy">
+ <di:waypoint x="168" y="120" />
+ <di:waypoint x="250" y="120" />
+ </bpmndi:BPMNEdge>
+ <bpmndi:BPMNEdge id="Flow_0htxke7_di" bpmnElement="Flow_0htxke7">
+ <di:waypoint x="540" y="120" />
+ <di:waypoint x="642" y="120" />
+ </bpmndi:BPMNEdge>
+ <bpmndi:BPMNEdge id="Flow_0niwe1y_di" bpmnElement="Flow_0niwe1y">
+ <di:waypoint x="350" y="120" />
+ <di:waypoint x="440" y="120" />
+ </bpmndi:BPMNEdge>
+ </bpmndi:BPMNPlane>
+ </bpmndi:BPMNDiagram>
+</bpmn:definitions>