Squashed 'SpiffWorkflow/' changes from 96ad2a2b0..73886584b

73886584b Merge pull request #315 from sartography/feature/new-task-states
a04fdd311 Merge remote-tracking branch 'origin/main' into feature/new-task-states
3d376bf9a documentation and comment updates
7e368ee4b copy edit
e7b9fe91c typo
eceef15a7 Called elements (#316)
5a0fd2774 add serialization migration
7211e67ee Merge pull request #314 from sartography/bugfix/data-object-references
403acc1f5 use same data objects & references in subprocesses after deserialization
c54091dee add two more states to spiff
fa04a14a7 clean up script engine a little bit
162a1c5f5 override create parser in spiff package to allow duplicate process names
98a1b37e0 Merge pull request #312 from sartography/bugfix/run-boundary-events-from-engine-steps
067d6a723 do not execute boundary events in catch
1c877dd76 send external events to top level workflow

git-subtree-dir: SpiffWorkflow
git-subtree-split: 73886584b17c7d11a9713d0c4526ed41e411fc45
This commit is contained in:
burnettk 2023-04-21 11:22:52 -04:00
parent f1b8cfcc07
commit c4f4e008d8
38 changed files with 977 additions and 72 deletions

1
.gitignore vendored
View File

@ -277,3 +277,4 @@ coverage.xml
.c9revisions
.idea
/venv
*~

View File

@ -45,7 +45,7 @@ tests-par:
echo " pip install unittest-parallel"; \
exit 1; \
fi
unittest-parallel --module-fixtures -vs tests/SpiffWorkflow -p \*Test.py -t .
unittest-parallel --module-fixtures -qbs tests/SpiffWorkflow -p \*Test.py -t .
.PHONY : tests-cov
tests-cov:

View File

@ -46,6 +46,8 @@ class ApprovalsTest(BpmnWorkflowTestCase):
def testRunThroughHappy(self):
self.do_next_named_step('First_Approval_Wins.Manager_Approval')
self.complete_subworkflow()
self.complete_subworkflow()
self.do_next_exclusive_step('Approvals.First_Approval_Wins_Done')
self.do_next_named_step('Approvals.Manager_Approval__P_')
@ -55,11 +57,15 @@ class ApprovalsTest(BpmnWorkflowTestCase):
self.do_next_named_step('Parallel_Approvals_SP.Step1')
self.do_next_named_step('Parallel_Approvals_SP.Manager_Approval')
self.do_next_named_step('Parallel_Approvals_SP.Supervisor_Approval')
self.complete_subworkflow()
self.complete_subworkflow()
self.do_next_exclusive_step('Approvals.Parallel_SP_Done')
def testRunThroughHappyOtherOrders(self):
self.do_next_named_step('First_Approval_Wins.Supervisor_Approval')
self.complete_subworkflow()
self.complete_subworkflow()
self.do_next_exclusive_step('Approvals.First_Approval_Wins_Done')
self.do_next_named_step('Approvals.Supervisor_Approval__P_')
@ -69,11 +75,15 @@ class ApprovalsTest(BpmnWorkflowTestCase):
self.do_next_named_step('Parallel_Approvals_SP.Manager_Approval')
self.do_next_named_step('Parallel_Approvals_SP.Step1')
self.do_next_named_step('Parallel_Approvals_SP.Supervisor_Approval')
self.complete_subworkflow()
self.complete_subworkflow()
self.do_next_exclusive_step('Approvals.Parallel_SP_Done')
def testSaveRestore(self):
self.do_next_named_step('First_Approval_Wins.Manager_Approval')
self.complete_subworkflow()
self.complete_subworkflow()
self.save_restore()
self.do_next_exclusive_step('Approvals.First_Approval_Wins_Done')
@ -86,12 +96,16 @@ class ApprovalsTest(BpmnWorkflowTestCase):
self.do_next_named_step('Parallel_Approvals_SP.Manager_Approval')
self.do_next_exclusive_step('Parallel_Approvals_SP.Step1')
self.do_next_exclusive_step('Parallel_Approvals_SP.Supervisor_Approval')
self.complete_subworkflow()
self.complete_subworkflow()
self.do_next_exclusive_step('Approvals.Parallel_SP_Done')
def testSaveRestoreWaiting(self):
self.do_next_named_step('First_Approval_Wins.Manager_Approval')
self.save_restore()
self.complete_subworkflow()
self.complete_subworkflow()
self.do_next_exclusive_step('Approvals.First_Approval_Wins_Done')
self.save_restore()
@ -108,6 +122,8 @@ class ApprovalsTest(BpmnWorkflowTestCase):
self.save_restore()
self.do_next_exclusive_step('Parallel_Approvals_SP.Supervisor_Approval')
self.save_restore()
self.complete_subworkflow()
self.complete_subworkflow()
self.do_next_exclusive_step('Approvals.Parallel_SP_Done')

View File

@ -118,6 +118,13 @@ class BpmnWorkflowTestCase(unittest.TestCase):
tasks[0].set_data(**set_attribs)
tasks[0].run()
def complete_subworkflow(self):
# A side effect of finer grained contol over task execution is that tasks require more explicit intervention
# to change states. Subworkflows tasks no longer go directly to ready when the subworkflow completes.
# So they may need to explicitly refreshed to become ready, and then run.
self.workflow.refresh_waiting_tasks()
self.workflow.do_engine_steps()
def save_restore(self):
script_engine = self.workflow.script_engine

View File

@ -6,6 +6,8 @@ from SpiffWorkflow.bpmn.PythonScriptEngine import PythonScriptEngine
from SpiffWorkflow.bpmn.workflow import BpmnWorkflow
from SpiffWorkflow.exceptions import WorkflowTaskException
from SpiffWorkflow.task import TaskState
from .BpmnWorkflowTestCase import BpmnWorkflowTestCase
__author__ = 'kellym'
@ -34,13 +36,12 @@ class CallActivityTest(BpmnWorkflowTestCase):
self.workflow = BpmnWorkflow(self.spec, self.subprocesses,
script_engine=CustomScriptEngine())
self.workflow.do_engine_steps()
self.complete_subworkflow()
self.assertTrue(self.workflow.is_completed())
self.assertIsInstance(self.workflow.script_engine, CustomScriptEngine)
if save_restore:
self.save_restore()
# We have to reset the script engine after deserialize.
self.workflow.script_engine = CustomScriptEngine()
# Get the subworkflow
sub_task = self.workflow.get_tasks_from_spec_name('Sub_Bpmn_Task')[0]
@ -54,6 +55,7 @@ class CallActivityTest(BpmnWorkflowTestCase):
# data should be removed in the final output as well.
self.workflow = BpmnWorkflow(self.spec, self.subprocesses)
self.workflow.do_engine_steps()
self.complete_subworkflow()
self.assertTrue(self.workflow.is_completed())
self.assertNotIn('remove_this_var', self.workflow.last_task.data.keys())
@ -66,6 +68,8 @@ class CallActivityTest(BpmnWorkflowTestCase):
self.assertEquals(2, len(context.exception.task_trace))
self.assertRegexpMatches(context.exception.task_trace[0], 'Create Data \(.*?call_activity_call_activity.bpmn\)')
self.assertRegexpMatches(context.exception.task_trace[1], 'Get Data Call Activity \(.*?call_activity_with_error.bpmn\)')
task = self.workflow.get_tasks_from_spec_name('Sub_Bpmn_Task')[0]
self.assertEqual(task.state, TaskState.ERROR)
def suite():
return unittest.TestLoader().loadTestsFromTestCase(CallActivityTest)

View File

@ -27,6 +27,8 @@ class CallActivitySubProcessPropTest(BpmnWorkflowTestCase):
def actualTest(self, save_restore=False):
self.workflow.do_engine_steps()
self.complete_subworkflow()
self.complete_subworkflow()
if save_restore:
self.save_restore()
self.assertTrue(self.workflow.is_completed())

View File

@ -38,6 +38,8 @@ class CustomInlineScriptTest(BpmnWorkflowTestCase):
def actual_test(self, save_restore):
if save_restore: self.save_restore()
self.workflow.do_engine_steps()
self.complete_subworkflow()
self.complete_subworkflow()
if save_restore: self.save_restore()
data = self.workflow.last_task.data
self.assertEqual(data['c1'], 'HELLO')
@ -49,8 +51,9 @@ class CustomInlineScriptTest(BpmnWorkflowTestCase):
ready_task.data = {'custom_function': "bill"}
with self.assertRaises(WorkflowTaskException) as e:
self.workflow.do_engine_steps()
self.assertTrue('' in str(e.exception))
self.assertTrue('custom_function' in str(e.exception))
task = self.workflow.get_tasks_from_spec_name('Activity_1y303ko')[0]
self.assertEqual(task.state, TaskState.ERROR)
def suite():

View File

@ -72,6 +72,9 @@ class DataObjectReferenceTest(BpmnWorkflowTestCase):
self.assertNotIn('obj_1', ready_tasks[0].data)
self.assertEqual(self.workflow.data['obj_1'], 'hello')
if save_restore:
self.save_restore()
# Make sure data objects are accessible inside a subprocess
self.workflow.do_engine_steps()
ready_tasks = self.workflow.get_ready_user_tasks()

View File

@ -1,14 +1,11 @@
# -*- coding: utf-8 -*-
import sys
import os
import unittest
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))
from SpiffWorkflow.bpmn.workflow import BpmnWorkflow
from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase
from SpiffWorkflow.exceptions import WorkflowException
from SpiffWorkflow.task import TaskState
from .BpmnWorkflowTestCase import BpmnWorkflowTestCase
__author__ = 'essweine'
@ -25,6 +22,8 @@ class ExclusiveGatewayNoDefaultTest(BpmnWorkflowTestCase):
first = self.workflow.get_tasks_from_spec_name('StartEvent_1')[0]
first.data = { 'x': 1 }
self.assertRaises(WorkflowException, self.workflow.do_engine_steps)
task = self.workflow.get_tasks_from_spec_name('Gateway_CheckValue')[0]
self.assertEqual(task.state, TaskState.ERROR)
def suite():
return unittest.TestLoader().loadTestsFromTestCase(ExclusiveGatewayNoDefaultTest)

View File

@ -62,6 +62,8 @@ class CallActivityDataTest(BpmnWorkflowTestCase):
self.assertNotIn('unused', task.data)
self.complete_subprocess()
# Refreshing causes the subprocess to become ready
self.workflow.refresh_waiting_tasks()
task = self.workflow.get_tasks(TaskState.READY)[0]
# Originals should not change
self.assertEqual(task.data['in_1'], 1)
@ -80,13 +82,11 @@ class CallActivityDataTest(BpmnWorkflowTestCase):
waiting = self.workflow.get_tasks(TaskState.WAITING)
def complete_subprocess(self):
# When we complete, the subworkflow task will move from WAITING to READY
waiting = self.workflow.get_tasks(TaskState.WAITING)
while len(waiting) > 0:
next_task = self.workflow.get_tasks(TaskState.READY)[0]
next_task.run()
waiting = self.workflow.get_tasks(TaskState.WAITING)
# Complete the ready tasks in the subprocess
ready = self.workflow.get_tasks(TaskState.READY)
while len(ready) > 0:
ready[0].run()
ready = self.workflow.get_tasks(TaskState.READY)
class IOSpecOnTaskTest(BpmnWorkflowTestCase):

View File

@ -1,5 +1,6 @@
from SpiffWorkflow.bpmn.workflow import BpmnWorkflow
from SpiffWorkflow.exceptions import WorkflowTaskException
from SpiffWorkflow.task import TaskState
from .BpmnWorkflowTestCase import BpmnWorkflowTestCase
@ -26,6 +27,8 @@ class InclusiveGatewayTest(BpmnWorkflowTestCase):
def testNoPathFromSecondGateway(self):
self.set_data({'v': 0, 'u': -1, 'w': -1})
self.assertRaises(WorkflowTaskException, self.workflow.do_engine_steps)
task = self.workflow.get_tasks_from_spec_name('second')[0]
self.assertEqual(task.state, TaskState.ERROR)
def testParallelCondition(self):
self.set_data({'v': 0, 'u': 1, 'w': 1})

View File

@ -25,9 +25,11 @@ class NestedProcessesTest(BpmnWorkflowTestCase):
self.assertEqual(1, len(self.workflow.get_tasks(TaskState.READY)))
self.do_next_named_step('Action3')
self.workflow.do_engine_steps()
self.complete_subworkflow()
self.complete_subworkflow()
self.complete_subworkflow()
self.save_restore()
self.assertEqual(
0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
self.assertEqual(0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
def suite():

View File

@ -32,6 +32,7 @@ class ParallelMultipleSplitsTest(BpmnWorkflowTestCase):
self.workflow.do_engine_steps()
self.do_next_named_step('SP 3 - Yes Task')
self.workflow.do_engine_steps()
self.complete_subworkflow()
self.do_next_named_step('Done')
self.workflow.do_engine_steps()

View File

@ -0,0 +1,24 @@
import os
import unittest
from SpiffWorkflow.bpmn.parser.BpmnParser import BpmnParser
from SpiffWorkflow.bpmn.parser.ProcessParser import ProcessParser
def _process_parser(bpmn_filename, process_id):
parser = BpmnParser()
bpmn_file = os.path.join(os.path.dirname(__file__), 'data', bpmn_filename)
parser.add_bpmn_file(bpmn_file)
return parser.get_process_parser(process_id)
class ProcessParserTest(unittest.TestCase):
def testReturnsEmptyListIfNoCallActivities(self):
parser = _process_parser("no-tasks.bpmn", "no_tasks")
assert parser.called_element_ids() == []
def testHandlesSingleCallActivity(self):
parser = _process_parser("single_call_activity.bpmn", "Process_p4pfxhq")
assert parser.called_element_ids() == ["SingleTask_Process"]
def testHandlesMultipleCallActivities(self):
parser = _process_parser("multiple_call_activities.bpmn", "Process_90mmqlw")
assert parser.called_element_ids() == ["Process_sypm122", "Process_diu8ta2", "Process_l14lar1"]

View File

@ -2,7 +2,7 @@ import json
from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase
from SpiffWorkflow.bpmn.PythonScriptEngine import PythonScriptEngine
from SpiffWorkflow.bpmn.PythonScriptEngineEnvironment import BasePythonScriptEngineEnvironment
from SpiffWorkflow.bpmn.PythonScriptEngineEnvironment import BasePythonScriptEngineEnvironment, TaskDataEnvironment
from SpiffWorkflow.bpmn.workflow import BpmnWorkflow
from SpiffWorkflow.task import TaskState
@ -23,10 +23,19 @@ class NonTaskDataExampleEnvironment(BasePythonScriptEngineEnvironment):
self.environment.update(external_methods or {})
exec(script, self.environment)
self.environment = {k: v for k, v in self.environment.items() if k not in external_methods}
return True
def user_defined_values(self):
return {k: v for k, v in self.environment.items() if k not in self.globals}
class AsyncScriptEnvironment(TaskDataEnvironment):
def execute(self, script, context, external_methods=None):
super().execute(script, context, external_methods)
return None
class PythonScriptEngineEnvironmentTest(BpmnWorkflowTestCase):
def setUp(self):
@ -78,3 +87,24 @@ class PythonScriptEngineEnvironmentTest(BpmnWorkflowTestCase):
task_data_len = len(json.dumps(task_data_to_check))
return task_data_len
class StartedTaskTest(BpmnWorkflowTestCase):
def setUp(self):
spec, subprocesses = self.load_workflow_spec('script-start.bpmn', 'Process_cozt5fu')
self.workflow = BpmnWorkflow(spec, subprocesses)
def testStartedState(self):
script_engine_environemnt = AsyncScriptEnvironment()
script_engine = PythonScriptEngine(environment=script_engine_environemnt)
self.workflow.script_engine = script_engine
self.workflow.do_engine_steps()
script_task = self.workflow.get_tasks_from_spec_name('script')[0]
self.assertEqual(script_task.state, TaskState.STARTED)
script_task.complete()
manual_task = self.workflow.get_tasks_from_spec_name('manual')[0]
manual_task.run()
self.workflow.do_engine_steps()
end = self.workflow.get_tasks_from_spec_name('End')[0]
self.assertDictEqual(end.data, {'x': 1, 'y': 2, 'z': 3})
self.assertTrue(self.workflow.is_completed())

View File

@ -35,7 +35,7 @@ class ResetSubProcessTest(BpmnWorkflowTestCase):
self.workflow.do_engine_steps()
top_level_task = self.workflow.get_ready_user_tasks()[0]
self.workflow.run_task_from_id(top_level_task.id)
top_level_task.run()
self.workflow.do_engine_steps()
task = self.workflow.get_ready_user_tasks()[0]
self.save_restore()
@ -50,11 +50,11 @@ class ResetSubProcessTest(BpmnWorkflowTestCase):
self.workflow.do_engine_steps()
self.assertEqual(1, len(self.workflow.get_ready_user_tasks()))
task = self.workflow.get_ready_user_tasks()[0]
self.workflow.run_task_from_id(task.id)
task.run()
self.workflow.do_engine_steps()
task = self.workflow.get_ready_user_tasks()[0]
self.assertEqual(task.get_name(),'SubTask2')
self.workflow.run_task_from_id(task.id)
task.run()
self.workflow.do_engine_steps()
task = self.workflow.get_tasks_from_spec_name('Task1')[0]
task.reset_token(self.workflow.last_task.data)
@ -62,19 +62,20 @@ class ResetSubProcessTest(BpmnWorkflowTestCase):
self.reload_save_restore()
task = self.workflow.get_ready_user_tasks()[0]
self.assertEqual(task.get_name(),'Task1')
self.workflow.run_task_from_id(task.id)
task.run()
self.workflow.do_engine_steps()
task = self.workflow.get_ready_user_tasks()[0]
self.assertEqual(task.get_name(),'Subtask2')
self.workflow.run_task_from_id(task.id)
task.run()
self.workflow.do_engine_steps()
task = self.workflow.get_ready_user_tasks()[0]
self.assertEqual(task.get_name(),'Subtask2A')
self.workflow.run_task_from_id(task.id)
task.run()
self.workflow.do_engine_steps()
self.complete_subworkflow()
task = self.workflow.get_ready_user_tasks()[0]
self.assertEqual(task.get_name(),'Task2')
self.workflow.run_task_from_id(task.id)
task.run()
self.workflow.do_engine_steps()
self.assertTrue(self.workflow.is_completed())

View File

@ -0,0 +1,62 @@
<?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" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
<bpmn:process id="Process_90mmqlw" isExecutable="true">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_0b6y930</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_0b6y930" sourceRef="StartEvent_1" targetRef="Activity_185dcnc" />
<bpmn:callActivity id="Activity_185dcnc" calledElement="Process_sypm122">
<bpmn:incoming>Flow_0b6y930</bpmn:incoming>
<bpmn:outgoing>Flow_0eaeoas</bpmn:outgoing>
</bpmn:callActivity>
<bpmn:sequenceFlow id="Flow_0eaeoas" sourceRef="Activity_185dcnc" targetRef="Activity_0rsppq2" />
<bpmn:callActivity id="Activity_0rsppq2" calledElement="Process_diu8ta2">
<bpmn:incoming>Flow_0eaeoas</bpmn:incoming>
<bpmn:outgoing>Flow_0hqm48x</bpmn:outgoing>
</bpmn:callActivity>
<bpmn:sequenceFlow id="Flow_0hqm48x" sourceRef="Activity_0rsppq2" targetRef="Activity_0d5dido" />
<bpmn:endEvent id="Event_0yflyfj">
<bpmn:incoming>Flow_0vhq9kk</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_0vhq9kk" sourceRef="Activity_0d5dido" targetRef="Event_0yflyfj" />
<bpmn:callActivity id="Activity_0d5dido" calledElement="Process_l14lar1">
<bpmn:incoming>Flow_0hqm48x</bpmn:incoming>
<bpmn:outgoing>Flow_0vhq9kk</bpmn:outgoing>
</bpmn:callActivity>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_90mmqlw">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="159" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1xwhx08_di" bpmnElement="Activity_185dcnc">
<dc:Bounds x="270" y="137" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0c85c6h_di" bpmnElement="Activity_0rsppq2">
<dc:Bounds x="430" y="137" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0yflyfj_di" bpmnElement="Event_0yflyfj">
<dc:Bounds x="752" y="159" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1d46rm4_di" bpmnElement="Activity_0d5dido">
<dc:Bounds x="590" y="137" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_0b6y930_di" bpmnElement="Flow_0b6y930">
<di:waypoint x="215" y="177" />
<di:waypoint x="270" y="177" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0eaeoas_di" bpmnElement="Flow_0eaeoas">
<di:waypoint x="370" y="177" />
<di:waypoint x="430" y="177" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0hqm48x_di" bpmnElement="Flow_0hqm48x">
<di:waypoint x="530" y="177" />
<di:waypoint x="590" y="177" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0vhq9kk_di" bpmnElement="Flow_0vhq9kk">
<di:waypoint x="690" y="177" />
<di:waypoint x="752" y="177" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -0,0 +1,26 @@
<?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" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
<bpmn:process id="no_tasks" name="No Tasks" isExecutable="true">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_184umot</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:endEvent id="Event_0qq9il3">
<bpmn:incoming>Flow_184umot</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_184umot" sourceRef="StartEvent_1" targetRef="Event_0qq9il3" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="no_tasks">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="159" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0qq9il3_di" bpmnElement="Event_0qq9il3">
<dc:Bounds x="272" y="159" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_184umot_di" bpmnElement="Flow_184umot">
<di:waypoint x="215" y="177" />
<di:waypoint x="272" y="177" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -0,0 +1,87 @@
<?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" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
<bpmn:process id="Process_cozt5fu" isExecutable="true">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_1r4la8u</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_1r4la8u" sourceRef="StartEvent_1" targetRef="Gateway_1b4ue4p" />
<bpmn:parallelGateway id="Gateway_1b4ue4p">
<bpmn:incoming>Flow_1r4la8u</bpmn:incoming>
<bpmn:outgoing>Flow_0rx8ly6</bpmn:outgoing>
<bpmn:outgoing>Flow_0m6kw0s</bpmn:outgoing>
</bpmn:parallelGateway>
<bpmn:sequenceFlow id="Flow_0rx8ly6" sourceRef="Gateway_1b4ue4p" targetRef="script" />
<bpmn:sequenceFlow id="Flow_0m6kw0s" sourceRef="Gateway_1b4ue4p" targetRef="manual" />
<bpmn:scriptTask id="script" name="script">
<bpmn:incoming>Flow_0rx8ly6</bpmn:incoming>
<bpmn:outgoing>Flow_1wcrqdb</bpmn:outgoing>
<bpmn:script>x, y = 1, 2
z = x + y</bpmn:script>
</bpmn:scriptTask>
<bpmn:manualTask id="manual" name="manual">
<bpmn:incoming>Flow_0m6kw0s</bpmn:incoming>
<bpmn:outgoing>Flow_0npa1g8</bpmn:outgoing>
</bpmn:manualTask>
<bpmn:sequenceFlow id="Flow_1wcrqdb" sourceRef="script" targetRef="Gateway_0lxkg29" />
<bpmn:sequenceFlow id="Flow_0npa1g8" sourceRef="manual" targetRef="Gateway_0lxkg29" />
<bpmn:parallelGateway id="Gateway_0lxkg29">
<bpmn:incoming>Flow_1wcrqdb</bpmn:incoming>
<bpmn:incoming>Flow_0npa1g8</bpmn:incoming>
<bpmn:outgoing>Flow_1vd5x0n</bpmn:outgoing>
</bpmn:parallelGateway>
<bpmn:endEvent id="Event_05ezfux">
<bpmn:incoming>Flow_1vd5x0n</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_1vd5x0n" sourceRef="Gateway_0lxkg29" targetRef="Event_05ezfux" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_cozt5fu">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="159" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_0wzobnw_di" bpmnElement="Gateway_1b4ue4p">
<dc:Bounds x="265" y="152" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1ufpwld_di" bpmnElement="script">
<dc:Bounds x="370" y="137" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0q6915b_di" bpmnElement="manual">
<dc:Bounds x="370" y="250" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_1rol38p_di" bpmnElement="Gateway_0lxkg29">
<dc:Bounds x="535" y="265" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_05ezfux_di" bpmnElement="Event_05ezfux">
<dc:Bounds x="632" y="272" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_1r4la8u_di" bpmnElement="Flow_1r4la8u">
<di:waypoint x="215" y="177" />
<di:waypoint x="265" y="177" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0rx8ly6_di" bpmnElement="Flow_0rx8ly6">
<di:waypoint x="315" y="177" />
<di:waypoint x="370" y="177" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0m6kw0s_di" bpmnElement="Flow_0m6kw0s">
<di:waypoint x="290" y="202" />
<di:waypoint x="290" y="290" />
<di:waypoint x="370" y="290" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1wcrqdb_di" bpmnElement="Flow_1wcrqdb">
<di:waypoint x="470" y="177" />
<di:waypoint x="560" y="177" />
<di:waypoint x="560" y="265" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0npa1g8_di" bpmnElement="Flow_0npa1g8">
<di:waypoint x="470" y="290" />
<di:waypoint x="535" y="290" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1vd5x0n_di" bpmnElement="Flow_1vd5x0n">
<di:waypoint x="585" y="290" />
<di:waypoint x="632" y="290" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -0,0 +1,563 @@
{
"serializer_version": "1.1",
"data": {},
"last_task": "3a4a6596-3b3d-4cd5-9724-cd1ccc263676",
"success": true,
"tasks": {
"d10fb568-6104-4a26-9081-e29c8eb42e70": {
"id": "d10fb568-6104-4a26-9081-e29c8eb42e70",
"parent": null,
"children": [
"f0a4e631-c30a-4444-b2b1-2cdc21179c65"
],
"last_state_change": 1681913960.451874,
"state": 32,
"task_spec": "Root",
"triggered": false,
"workflow_name": "main",
"internal_data": {},
"data": {}
},
"f0a4e631-c30a-4444-b2b1-2cdc21179c65": {
"id": "f0a4e631-c30a-4444-b2b1-2cdc21179c65",
"parent": "d10fb568-6104-4a26-9081-e29c8eb42e70",
"children": [
"3468f48a-c493-4731-9484-0821d046a0bc"
],
"last_state_change": 1681913960.4591289,
"state": 32,
"task_spec": "Start",
"triggered": false,
"workflow_name": "main",
"internal_data": {},
"data": {}
},
"3468f48a-c493-4731-9484-0821d046a0bc": {
"id": "3468f48a-c493-4731-9484-0821d046a0bc",
"parent": "f0a4e631-c30a-4444-b2b1-2cdc21179c65",
"children": [
"0366c1b3-d55e-42e4-a6fd-db2d6a1940eb"
],
"last_state_change": 1681913960.460862,
"state": 32,
"task_spec": "StartEvent_1",
"triggered": false,
"workflow_name": "main",
"internal_data": {
"event_fired": true
},
"data": {}
},
"0366c1b3-d55e-42e4-a6fd-db2d6a1940eb": {
"id": "0366c1b3-d55e-42e4-a6fd-db2d6a1940eb",
"parent": "3468f48a-c493-4731-9484-0821d046a0bc",
"children": [
"afd334bf-f987-46b3-b6df-779562c4b4bf",
"ad8b1640-55ac-4ff5-b07e-16c0b7c92976"
],
"last_state_change": 1681913960.4621637,
"state": 32,
"task_spec": "task_1.BoundaryEventParent",
"triggered": false,
"workflow_name": "main",
"internal_data": {},
"data": {}
},
"afd334bf-f987-46b3-b6df-779562c4b4bf": {
"id": "afd334bf-f987-46b3-b6df-779562c4b4bf",
"parent": "0366c1b3-d55e-42e4-a6fd-db2d6a1940eb",
"children": [
"3a4a6596-3b3d-4cd5-9724-cd1ccc263676"
],
"last_state_change": 1681913960.4634154,
"state": 32,
"task_spec": "task_1",
"triggered": false,
"workflow_name": "main",
"internal_data": {},
"data": {}
},
"3a4a6596-3b3d-4cd5-9724-cd1ccc263676": {
"id": "3a4a6596-3b3d-4cd5-9724-cd1ccc263676",
"parent": "afd334bf-f987-46b3-b6df-779562c4b4bf",
"children": [
"8ee8a04c-e784-4419-adb4-7c7f99f72bf6",
"00c5b447-760e-47dc-a77b-cffbf893d098"
],
"last_state_change": 1681913960.4667528,
"state": 32,
"task_spec": "Gateway_1eg2w56",
"triggered": false,
"workflow_name": "main",
"internal_data": {},
"data": {}
},
"8ee8a04c-e784-4419-adb4-7c7f99f72bf6": {
"id": "8ee8a04c-e784-4419-adb4-7c7f99f72bf6",
"parent": "3a4a6596-3b3d-4cd5-9724-cd1ccc263676",
"children": [
"cee7ab8e-d50b-4681-94f2-51bbd8dd6df1"
],
"last_state_change": 1681913960.4669333,
"state": 16,
"task_spec": "task_2",
"triggered": false,
"workflow_name": "main",
"internal_data": {},
"data": {}
},
"cee7ab8e-d50b-4681-94f2-51bbd8dd6df1": {
"id": "cee7ab8e-d50b-4681-94f2-51bbd8dd6df1",
"parent": "8ee8a04c-e784-4419-adb4-7c7f99f72bf6",
"children": [
"4695356f-8db1-48f6-a8bb-d610b2da7a63"
],
"last_state_change": 1681913960.454116,
"state": 4,
"task_spec": "Gateway_1dpu3vt",
"triggered": false,
"workflow_name": "main",
"internal_data": {},
"data": {}
},
"4695356f-8db1-48f6-a8bb-d610b2da7a63": {
"id": "4695356f-8db1-48f6-a8bb-d610b2da7a63",
"parent": "cee7ab8e-d50b-4681-94f2-51bbd8dd6df1",
"children": [
"f4ab0e07-d985-412f-aca0-369bd29797e1"
],
"last_state_change": 1681913960.45428,
"state": 4,
"task_spec": "Event_1deqprp",
"triggered": false,
"workflow_name": "main",
"internal_data": {},
"data": {}
},
"f4ab0e07-d985-412f-aca0-369bd29797e1": {
"id": "f4ab0e07-d985-412f-aca0-369bd29797e1",
"parent": "4695356f-8db1-48f6-a8bb-d610b2da7a63",
"children": [
"e326e6ec-f20d-4171-8133-24b160ad3404"
],
"last_state_change": 1681913960.4544458,
"state": 4,
"task_spec": "main.EndJoin",
"triggered": false,
"workflow_name": "main",
"internal_data": {},
"data": {}
},
"e326e6ec-f20d-4171-8133-24b160ad3404": {
"id": "e326e6ec-f20d-4171-8133-24b160ad3404",
"parent": "f4ab0e07-d985-412f-aca0-369bd29797e1",
"children": [],
"last_state_change": 1681913960.4546103,
"state": 4,
"task_spec": "End",
"triggered": false,
"workflow_name": "main",
"internal_data": {},
"data": {}
},
"00c5b447-760e-47dc-a77b-cffbf893d098": {
"id": "00c5b447-760e-47dc-a77b-cffbf893d098",
"parent": "3a4a6596-3b3d-4cd5-9724-cd1ccc263676",
"children": [
"c57e4be7-670c-41aa-9740-9fff831f6ccd"
],
"last_state_change": 1681913960.4671006,
"state": 16,
"task_spec": "task_3",
"triggered": false,
"workflow_name": "main",
"internal_data": {},
"data": {}
},
"c57e4be7-670c-41aa-9740-9fff831f6ccd": {
"id": "c57e4be7-670c-41aa-9740-9fff831f6ccd",
"parent": "00c5b447-760e-47dc-a77b-cffbf893d098",
"children": [
"ee2c8edc-5d5e-4fc2-ba4b-1801d000c6c3"
],
"last_state_change": 1681913960.454881,
"state": 4,
"task_spec": "Gateway_1dpu3vt",
"triggered": false,
"workflow_name": "main",
"internal_data": {},
"data": {}
},
"ee2c8edc-5d5e-4fc2-ba4b-1801d000c6c3": {
"id": "ee2c8edc-5d5e-4fc2-ba4b-1801d000c6c3",
"parent": "c57e4be7-670c-41aa-9740-9fff831f6ccd",
"children": [
"91a213bf-bef6-40fa-b0a4-7c7f58552184"
],
"last_state_change": 1681913960.4550629,
"state": 4,
"task_spec": "Event_1deqprp",
"triggered": false,
"workflow_name": "main",
"internal_data": {},
"data": {}
},
"91a213bf-bef6-40fa-b0a4-7c7f58552184": {
"id": "91a213bf-bef6-40fa-b0a4-7c7f58552184",
"parent": "ee2c8edc-5d5e-4fc2-ba4b-1801d000c6c3",
"children": [
"8166e255-1d17-4f94-8c0e-82cefe8500fd"
],
"last_state_change": 1681913960.4552596,
"state": 4,
"task_spec": "main.EndJoin",
"triggered": false,
"workflow_name": "main",
"internal_data": {},
"data": {}
},
"8166e255-1d17-4f94-8c0e-82cefe8500fd": {
"id": "8166e255-1d17-4f94-8c0e-82cefe8500fd",
"parent": "91a213bf-bef6-40fa-b0a4-7c7f58552184",
"children": [],
"last_state_change": 1681913960.455456,
"state": 4,
"task_spec": "End",
"triggered": false,
"workflow_name": "main",
"internal_data": {},
"data": {}
},
"ad8b1640-55ac-4ff5-b07e-16c0b7c92976": {
"id": "ad8b1640-55ac-4ff5-b07e-16c0b7c92976",
"parent": "0366c1b3-d55e-42e4-a6fd-db2d6a1940eb",
"children": [],
"last_state_change": 1681913960.463645,
"state": 64,
"task_spec": "signal",
"triggered": false,
"workflow_name": "main",
"internal_data": {
"event_fired": false
},
"data": {}
}
},
"root": "d10fb568-6104-4a26-9081-e29c8eb42e70",
"spec": {
"name": "main",
"description": "main",
"file": "/home/essweine/work/sartography/code/SpiffWorkflow/tests/SpiffWorkflow/bpmn/data/diagram_1.bpmn",
"task_specs": {
"Start": {
"id": "main_1",
"name": "Start",
"description": "",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [],
"outputs": [
"StartEvent_1"
],
"typename": "StartTask"
},
"main.EndJoin": {
"id": "main_2",
"name": "main.EndJoin",
"description": "",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"Event_1deqprp"
],
"outputs": [
"End"
],
"typename": "_EndJoin"
},
"End": {
"id": "main_3",
"name": "End",
"description": "",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"main.EndJoin"
],
"outputs": [],
"typename": "Simple"
},
"StartEvent_1": {
"id": "main_4",
"name": "StartEvent_1",
"description": null,
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"Start"
],
"outputs": [
"task_1.BoundaryEventParent"
],
"lane": null,
"documentation": null,
"position": {
"x": 179.0,
"y": 99.0
},
"data_input_associations": [],
"data_output_associations": [],
"io_specification": null,
"event_definition": {
"internal": false,
"external": false,
"typename": "NoneEventDefinition"
},
"typename": "StartEvent",
"extensions": {}
},
"task_1": {
"id": "main_5",
"name": "task_1",
"description": "Task 1",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"task_1.BoundaryEventParent"
],
"outputs": [
"Gateway_1eg2w56"
],
"lane": null,
"documentation": null,
"position": {
"x": 270.0,
"y": 77.0
},
"data_input_associations": [],
"data_output_associations": [],
"io_specification": null,
"typename": "NoneTask",
"extensions": {}
},
"task_1.BoundaryEventParent": {
"id": "main_6",
"name": "task_1.BoundaryEventParent",
"description": "",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"StartEvent_1"
],
"outputs": [
"task_1",
"signal"
],
"lane": null,
"documentation": null,
"position": {
"x": 0,
"y": 0
},
"data_input_associations": [],
"data_output_associations": [],
"io_specification": null,
"main_child_task_spec": "task_1",
"typename": "_BoundaryEventParent"
},
"signal": {
"id": "main_7",
"name": "signal",
"description": "Signal Event",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"task_1.BoundaryEventParent"
],
"outputs": [],
"lane": null,
"documentation": null,
"position": {
"x": 302.0,
"y": 139.0
},
"data_input_associations": [],
"data_output_associations": [],
"io_specification": null,
"event_definition": {
"internal": true,
"external": true,
"name": "Signal_08n3u9r",
"typename": "SignalEventDefinition"
},
"cancel_activity": true,
"typename": "BoundaryEvent",
"extensions": {}
},
"Gateway_1eg2w56": {
"id": "main_8",
"name": "Gateway_1eg2w56",
"description": null,
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"task_1"
],
"outputs": [
"task_2",
"task_3"
],
"lane": null,
"documentation": null,
"position": {
"x": 425.0,
"y": 92.0
},
"data_input_associations": [],
"data_output_associations": [],
"io_specification": null,
"split_task": null,
"threshold": null,
"cancel": false,
"typename": "ParallelGateway",
"extensions": {}
},
"task_2": {
"id": "main_9",
"name": "task_2",
"description": "Task 2",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"Gateway_1eg2w56"
],
"outputs": [
"Gateway_1dpu3vt"
],
"lane": null,
"documentation": null,
"position": {
"x": 530.0,
"y": 77.0
},
"data_input_associations": [],
"data_output_associations": [],
"io_specification": null,
"typename": "NoneTask",
"extensions": {}
},
"Gateway_1dpu3vt": {
"id": "main_10",
"name": "Gateway_1dpu3vt",
"description": null,
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"task_2",
"task_3"
],
"outputs": [
"Event_1deqprp"
],
"lane": null,
"documentation": null,
"position": {
"x": 685.0,
"y": 92.0
},
"data_input_associations": [],
"data_output_associations": [],
"io_specification": null,
"split_task": null,
"threshold": null,
"cancel": false,
"typename": "ParallelGateway",
"extensions": {}
},
"Event_1deqprp": {
"id": "main_11",
"name": "Event_1deqprp",
"description": null,
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"Gateway_1dpu3vt"
],
"outputs": [
"main.EndJoin"
],
"lane": null,
"documentation": null,
"position": {
"x": 792.0,
"y": 99.0
},
"data_input_associations": [],
"data_output_associations": [],
"io_specification": null,
"event_definition": {
"internal": false,
"external": false,
"typename": "NoneEventDefinition"
},
"typename": "EndEvent",
"extensions": {}
},
"task_3": {
"id": "main_12",
"name": "task_3",
"description": "Task 3",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"Gateway_1eg2w56"
],
"outputs": [
"Gateway_1dpu3vt"
],
"lane": null,
"documentation": null,
"position": {
"x": 530.0,
"y": 190.0
},
"data_input_associations": [],
"data_output_associations": [],
"io_specification": null,
"typename": "NoneTask",
"extensions": {}
},
"Root": {
"id": "main_13",
"name": "Root",
"description": "",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [],
"outputs": [],
"typename": "Simple"
}
},
"io_specification": null,
"data_objects": {},
"correlation_keys": {},
"typename": "BpmnProcessSpec"
},
"subprocess_specs": {},
"subprocesses": {},
"bpmn_messages": [],
"correlations": {}
}

View File

@ -0,0 +1,38 @@
<?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" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
<bpmn:process id="Process_p4pfxhq" isExecutable="true">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_04380wl</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_04380wl" sourceRef="StartEvent_1" targetRef="Activity_0q1z4d4" />
<bpmn:endEvent id="Event_05ktmeu">
<bpmn:incoming>Flow_1io4ukf</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_1io4ukf" sourceRef="Activity_0q1z4d4" targetRef="Event_05ktmeu" />
<bpmn:callActivity id="Activity_0q1z4d4" calledElement="SingleTask_Process">
<bpmn:incoming>Flow_04380wl</bpmn:incoming>
<bpmn:outgoing>Flow_1io4ukf</bpmn:outgoing>
</bpmn:callActivity>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_p4pfxhq">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="159" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_05ktmeu_di" bpmnElement="Event_05ktmeu">
<dc:Bounds x="432" y="159" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0tmeu68_di" bpmnElement="Activity_0q1z4d4">
<dc:Bounds x="270" y="137" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_04380wl_di" bpmnElement="Flow_04380wl">
<di:waypoint x="215" y="177" />
<di:waypoint x="270" y="177" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1io4ukf_di" bpmnElement="Flow_1io4ukf">
<di:waypoint x="370" y="177" />
<di:waypoint x="432" y="177" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -50,6 +50,7 @@ class ActionManagementTest(BpmnWorkflowTestCase):
self.do_next_named_step("Complete Work", choice="Done")
self.workflow.do_engine_steps()
self.complete_subworkflow()
self.assertTrue(self.workflow.is_completed())
@ -91,6 +92,7 @@ class ActionManagementTest(BpmnWorkflowTestCase):
self.do_next_named_step("Complete Work", choice="Done")
self.workflow.do_engine_steps()
self.complete_subworkflow()
self.assertTrue(self.workflow.is_completed())

View File

@ -80,6 +80,7 @@ class CallActivityEscalationTest(BpmnWorkflowTestCase):
for task in self.workflow.get_tasks(TaskState.READY):
task.set_data(should_escalate=False)
self.workflow.do_engine_steps()
self.complete_subworkflow()
self.save_restore()
self.workflow.run_all()
self.assertEqual(True, self.workflow.is_completed())

View File

@ -28,6 +28,7 @@ class MessageInterruptsSpTest(BpmnWorkflowTestCase):
self.do_next_exclusive_step('Do Something In a Subprocess')
self.workflow.do_engine_steps()
self.complete_subworkflow()
self.save_restore()
self.do_next_exclusive_step('Ack Subprocess Done')
@ -35,8 +36,7 @@ class MessageInterruptsSpTest(BpmnWorkflowTestCase):
self.save_restore()
self.workflow.do_engine_steps()
self.assertEqual(
0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
self.assertEqual(0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
def testRunThroughInterruptSaveAndRestore(self):
@ -58,8 +58,7 @@ class MessageInterruptsSpTest(BpmnWorkflowTestCase):
self.save_restore()
self.workflow.do_engine_steps()
self.assertEqual(
0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
self.assertEqual(0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
def suite():

View File

@ -30,13 +30,13 @@ class MessageInterruptsTest(BpmnWorkflowTestCase):
self.save_restore()
self.workflow.do_engine_steps()
self.complete_subworkflow()
self.assertEqual(0, len(self.workflow.get_tasks(TaskState.WAITING)))
self.save_restore()
self.workflow.do_engine_steps()
self.assertEqual(
0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
self.assertEqual(0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
def testRunThroughMessageInterruptSaveAndRestore(self):
@ -61,9 +61,9 @@ class MessageInterruptsTest(BpmnWorkflowTestCase):
self.save_restore()
self.workflow.do_engine_steps()
self.complete_subworkflow()
self.save_restore()
self.assertEqual(
0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
self.assertEqual(0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
def testRunThroughHappy(self):
@ -77,11 +77,11 @@ class MessageInterruptsTest(BpmnWorkflowTestCase):
self.do_next_exclusive_step('Do Something That Takes A Long Time')
self.workflow.do_engine_steps()
self.complete_subworkflow()
self.assertEqual(0, len(self.workflow.get_tasks(TaskState.WAITING)))
self.workflow.do_engine_steps()
self.assertEqual(
0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
self.assertEqual(0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
def testRunThroughMessageInterrupt(self):
@ -101,8 +101,8 @@ class MessageInterruptsTest(BpmnWorkflowTestCase):
self.do_next_exclusive_step('Acknowledge Interrupt Message')
self.workflow.do_engine_steps()
self.assertEqual(
0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
self.complete_subworkflow()
self.assertEqual(0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
def suite():

View File

@ -31,13 +31,13 @@ class MessageNonInterruptTest(BpmnWorkflowTestCase):
self.save_restore()
self.workflow.do_engine_steps()
self.complete_subworkflow()
self.assertEqual(0, len(self.workflow.get_tasks(TaskState.WAITING)))
self.save_restore()
self.workflow.do_engine_steps()
self.assertEqual(
0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
self.assertEqual(0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
def testRunThroughMessageInterruptSaveAndRestore(self):
@ -71,8 +71,8 @@ class MessageNonInterruptTest(BpmnWorkflowTestCase):
self.save_restore()
self.workflow.do_engine_steps()
self.assertEqual(
0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
self.complete_subworkflow()
self.assertEqual(0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
def testRunThroughHappy(self):
@ -87,11 +87,11 @@ class MessageNonInterruptTest(BpmnWorkflowTestCase):
self.do_next_exclusive_step('Do Something That Takes A Long Time')
self.workflow.do_engine_steps()
self.complete_subworkflow()
self.assertEqual(0, len(self.workflow.get_tasks(TaskState.WAITING)))
self.workflow.do_engine_steps()
self.assertEqual(
0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
self.assertEqual(0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
def testRunThroughMessageInterrupt(self):
@ -118,8 +118,8 @@ class MessageNonInterruptTest(BpmnWorkflowTestCase):
self.do_next_named_step('Do Something That Takes A Long Time')
self.workflow.do_engine_steps()
self.assertEqual(
0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
self.complete_subworkflow()
self.assertEqual(0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
def testRunThroughMessageInterruptOtherOrder(self):
@ -145,8 +145,8 @@ class MessageNonInterruptTest(BpmnWorkflowTestCase):
self.do_next_named_step('Acknowledge Non-Interrupt Message')
self.workflow.do_engine_steps()
self.assertEqual(
0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
self.complete_subworkflow()
self.assertEqual(0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
def testRunThroughMessageInterruptOtherOrderSaveAndRestore(self):
@ -177,8 +177,8 @@ class MessageNonInterruptTest(BpmnWorkflowTestCase):
self.save_restore()
self.workflow.do_engine_steps()
self.assertEqual(
0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
self.complete_subworkflow()
self.assertEqual(0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
def suite():

View File

@ -28,6 +28,7 @@ class MessageNonInterruptsSpTest(BpmnWorkflowTestCase):
self.do_next_exclusive_step('Do Something In a Subprocess')
self.workflow.do_engine_steps()
self.complete_subworkflow()
self.save_restore()
self.do_next_exclusive_step('Ack Subprocess Done')
@ -35,8 +36,7 @@ class MessageNonInterruptsSpTest(BpmnWorkflowTestCase):
self.save_restore()
self.workflow.do_engine_steps()
self.assertEqual(
0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
self.assertEqual(0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
def testRunThroughMessageSaveAndRestore(self):
@ -53,6 +53,7 @@ class MessageNonInterruptsSpTest(BpmnWorkflowTestCase):
self.do_next_named_step('Do Something In a Subprocess')
self.workflow.do_engine_steps()
self.complete_subworkflow()
self.save_restore()
self.do_next_named_step('Ack Subprocess Done')
@ -64,8 +65,7 @@ class MessageNonInterruptsSpTest(BpmnWorkflowTestCase):
self.save_restore()
self.workflow.do_engine_steps()
self.assertEqual(
0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
self.assertEqual(0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
def testRunThroughMessageOrder2SaveAndRestore(self):
@ -81,6 +81,7 @@ class MessageNonInterruptsSpTest(BpmnWorkflowTestCase):
self.workflow.catch(MessageEventDefinition('Test Message'))
self.do_next_named_step('Do Something In a Subprocess')
self.workflow.do_engine_steps()
self.complete_subworkflow()
self.save_restore()
self.do_next_named_step('Acknowledge SP Parallel Message')
@ -92,8 +93,7 @@ class MessageNonInterruptsSpTest(BpmnWorkflowTestCase):
self.save_restore()
self.workflow.do_engine_steps()
self.assertEqual(
0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
self.assertEqual(0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
def testRunThroughMessageOrder3SaveAndRestore(self):
@ -114,6 +114,7 @@ class MessageNonInterruptsSpTest(BpmnWorkflowTestCase):
self.do_next_named_step('Do Something In a Subprocess')
self.workflow.do_engine_steps()
self.complete_subworkflow()
self.save_restore()
self.do_next_named_step('Ack Subprocess Done')
@ -121,8 +122,7 @@ class MessageNonInterruptsSpTest(BpmnWorkflowTestCase):
self.save_restore()
self.workflow.do_engine_steps()
self.assertEqual(
0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
self.assertEqual(0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
def suite():

View File

@ -27,12 +27,11 @@ class MessagesTest(BpmnWorkflowTestCase):
self.workflow.catch(MessageEventDefinition('Test Message'))
self.assertEqual(1, len(self.workflow.get_tasks(TaskState.READY)))
self.assertEqual(
'Test Message', self.workflow.get_tasks(TaskState.READY)[0].task_spec.description)
self.assertEqual('Test Message', self.workflow.get_tasks(TaskState.READY)[0].task_spec.description)
self.workflow.do_engine_steps()
self.assertEqual(
0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
self.complete_subworkflow()
self.assertEqual(0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
def testRunThroughSaveAndRestore(self):
@ -52,8 +51,8 @@ class MessagesTest(BpmnWorkflowTestCase):
self.save_restore()
self.workflow.do_engine_steps()
self.assertEqual(
0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
self.complete_subworkflow()
self.assertEqual(0, len(self.workflow.get_tasks(TaskState.READY | TaskState.WAITING)))
def suite():

View File

@ -19,6 +19,7 @@ class MultipleThrowEventIntermediateCatchTest(BpmnWorkflowTestCase):
if save_restore:
self.save_restore()
self.workflow.do_engine_steps()
self.complete_subworkflow()
self.assertEqual(len(self.workflow.get_waiting_tasks()), 0)
self.assertEqual(self.workflow.is_completed(), True)
@ -44,4 +45,5 @@ class MultipleThrowEventStartsEventTest(BpmnWorkflowTestCase):
self.assertEqual(len(ready_tasks), 1)
ready_tasks[0].run()
self.workflow.do_engine_steps()
self.complete_subworkflow()
self.assertEqual(self.workflow.is_completed(), True)

View File

@ -65,7 +65,9 @@ class NITimerDurationTest(BpmnWorkflowTestCase):
task.run()
self.workflow.refresh_waiting_tasks()
self.workflow.do_engine_steps()
self.assertEqual(self.workflow.is_completed(),True)
self.workflow.do_engine_steps()
self.complete_subworkflow()
self.assertEqual(self.workflow.is_completed(), True)
self.assertEqual(self.workflow.last_task.data, {'work_done': 'Yes', 'delay_reason': 'Just Because'})

View File

@ -25,6 +25,7 @@ class TransactionSubprocessTest(BpmnWorkflowTestCase):
ready_tasks[0].update_data({'quantity': 2})
ready_tasks[0].run()
self.workflow.do_engine_steps()
self.complete_subworkflow()
self.assertIn('value', self.workflow.last_task.data)
# Check that workflow and next task completed

View File

@ -23,6 +23,10 @@ class Version_1_0_Test(BaseTestCase):
self.assertEqual('Action3', ready_tasks[0].task_spec.description)
ready_tasks[0].run()
wf.do_engine_steps()
wf.refresh_waiting_tasks()
wf.do_engine_steps()
wf.refresh_waiting_tasks()
wf.do_engine_steps()
self.assertEqual(True, wf.is_completed())
@ -34,12 +38,16 @@ class Version_1_1_Test(BaseTestCase):
wf.script_engine = PythonScriptEngine(environment=TaskDataEnvironment({"time": time}))
wf.refresh_waiting_tasks()
wf.do_engine_steps()
wf.refresh_waiting_tasks()
wf.do_engine_steps()
self.assertTrue(wf.is_completed())
def test_convert_data_specs(self):
fn = os.path.join(self.DATA_DIR, 'serialization', 'v1.1-data.json')
wf = self.serializer.deserialize_json(open(fn).read())
wf.do_engine_steps()
wf.refresh_waiting_tasks()
wf.do_engine_steps()
self.assertTrue(wf.is_completed())
def test_convert_exclusive_gateway(self):
@ -71,3 +79,16 @@ class Version_1_1_Test(BaseTestCase):
wf.refresh_waiting_tasks()
self.assertTrue(wf.is_completed())
self.assertEqual(wf.last_task.data['counter'], 20)
def test_update_task_states(self):
fn = os.path.join(self.DATA_DIR, 'serialization', 'v1.1-task-states.json')
wf = self.serializer.deserialize_json(open(fn).read())
start = wf.get_tasks_from_spec_name('Start')[0]
self.assertEqual(start.state, TaskState.COMPLETED)
signal = wf.get_tasks_from_spec_name('signal')[0]
self.assertEqual(signal.state, TaskState.CANCELLED)
ready_tasks = wf.get_tasks(TaskState.READY)
while len(ready_tasks) > 0:
ready_tasks[0].run()
ready_tasks = wf.get_tasks(TaskState.READY)
self.assertTrue(wf.is_completed())

View File

@ -41,7 +41,7 @@ class CallActivityMessageTest(BaseTestCase):
current_task.update_data(step[1])
current_task.run()
self.workflow.do_engine_steps()
self.workflow.refresh_waiting_tasks()
self.complete_subworkflow()
if save_restore: self.save_restore()
ready_tasks = self.workflow.get_tasks(TaskState.READY)
self.assertEqual(self.workflow.is_completed(),True,'Expected the workflow to be complete at this point')

View File

@ -50,7 +50,7 @@ class ExternalMessageBoundaryTest(BaseTestCase):
self.workflow.catch(MessageEventDefinition('reset', payload='SomethingDrastic', result_var='reset_var'))
ready_tasks = self.workflow.get_tasks(TaskState.READY)
# The user activity was cancelled and we should continue from the boundary event
self.assertEqual(1, len(ready_tasks),'Expected to have two ready tasks')
self.assertEqual(2, len(ready_tasks), 'Expected to have two ready tasks')
event = self.workflow.get_tasks_from_spec_name('Event_19detfv')[0]
event.run()
self.assertEqual('SomethingDrastic', event.data['reset_var'])

View File

@ -84,6 +84,7 @@ class NIMessageBoundaryTest(BaseTestCase):
task.data['work_completed'] = 'Lots of Stuff'
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
self.complete_subworkflow()
self.assertEqual(self.workflow.is_completed(),True)
self.assertEqual(self.workflow.last_task.data,{'Event_InterruptBoundary_Response': 'Youre late!',
'flag_task': 'Yes',

View File

@ -51,7 +51,7 @@ class ResetTokenTestSubProcess(BaseTestCase):
firsttaskid = task.id
self.assertEqual(step['taskname'], task.task_spec.name)
task.update_data({step['formvar']: step['answer']})
self.workflow.run_task_from_id(task.id)
task.run()
self.workflow.do_engine_steps()
if save_restore:
self.save_restore()
@ -75,8 +75,9 @@ class ResetTokenTestSubProcess(BaseTestCase):
task = self.workflow.get_ready_user_tasks()[0]
self.assertEqual(step['taskname'], task.task_spec.name)
task.update_data({step['formvar']: step['answer']})
self.workflow.run_task_from_id(task.id)
task.run()
self.workflow.do_engine_steps()
self.complete_subworkflow()
if save_restore:
self.save_restore()

View File

@ -31,8 +31,9 @@ class SubWorkflowTest(BaseTestCase):
task = self.workflow.get_ready_user_tasks()[0]
self.assertEqual("Activity_"+answer, task.task_spec.name)
task.update_data({"Field"+answer: answer})
self.workflow.run_task_from_id(task.id)
task.run()
self.workflow.do_engine_steps()
self.complete_subworkflow()
if save_restore: self.save_restore()
self.assertEqual(self.workflow.last_task.data,{'FieldA': 'A',

View File

@ -58,6 +58,8 @@ class PrescriptPostsciptTest(BaseTestCase):
self.workflow.do_engine_steps()
ex = se.exception
self.assertIn("Error occurred in the Pre-Script", str(ex))
task = self.workflow.get_tasks_from_spec_name('Activity_1iqs4li')[0]
self.assertEqual(task.state, TaskState.ERROR)
def call_activity_test(self, save_restore=False):
@ -82,3 +84,4 @@ class PrescriptPostsciptTest(BaseTestCase):
ready_tasks = self.workflow.get_tasks(TaskState.READY)
ready_tasks[0].set_data(**data)
self.workflow.do_engine_steps()
self.complete_subworkflow()