Squashed 'SpiffWorkflow/' changes from bee868d38..96ad2a2b0

96ad2a2b0 Merge pull request #311 from sartography/feature/error-message-on-bad-child-task
3fb69038d Merge remote-tracking branch 'origin/main' into feature/error-message-on-bad-child-task
df703ebb8 Merge remote-tracking branch 'origin/feature/add_task_not_found_error'
d6e244bcf also raise TaskNotFoundException from bpmn workflow w/ burnettk
37d7ae679 Merge pull request #310 from sartography/feature/add_task_not_found_error
7f4d38ce2 give us a better error if for some reason a task does not exist
b98efbd20 added an exception for task not found w/ burnettk
e1add839d Merge pull request #308 from sartography/bugfix/execute-event-gateways-on-ready
964c0231a do not predict tasks when deserializing, add method to predict all unfinished tasks
114f87aa9 update event gateway
62454c99c Merge pull request #307 from sartography/feature/standardize-task-execution
a087d29ea update task_spec._run to return a boolean & misc cleanup
9864d753d reenable recursion test
1bb1246a0 rename methods & move ready_before tasks from run to ready
12ce08519 move event task execution to run
d51bb68eb cleanup predictions
5e05458a3 make all tasks execute when run rather than completed (except bpmn events)
273d7b325 create a run method for tasks
3c3345c85 Merge pull request #306 from sartography/feature/create-core-test-package
ed85547d7 hopefully fix CI job, also update some deprecated assertions
80d68c231 cleanup around finding tasks
ea5ffff41 create tests based on individual patterns
afe41fba1 move core tests into one package
c075d52bc remove locks from task spec -- they don't do anything
d78c7cc04 reorganize so that related methods are near each other
f162aac43 Merge pull request #305 from sartography/feature/remove-loop-reset
6cad29817 'fix' old serializer to remove loop resets -- or at least get the tests to pass
a95d2fc12 add serialization migration that removes loop resets
c076175c8 account for DST in timers
42b483054 Merge pull request #303 from sartography/bugfix/execute-tasks-on-ready
2bb08aae1 update script/service tasks to execute on ready
0bd23a0ab fix scripts in business rule tasks
13034aaf1 prevent loop reset tasks from being inserted
3fb80518d update join execution model

git-subtree-dir: SpiffWorkflow
git-subtree-split: 96ad2a2b060deb445c39374f065690023351de19
This commit is contained in:
burnettk 2023-04-07 11:46:14 -04:00
parent ce6de53a76
commit f1b8cfcc07
206 changed files with 1585 additions and 1735 deletions

View File

@ -19,7 +19,7 @@ workflow = Workflow(spec)
# Execute until all tasks are done or require manual intervention.
# For the sake of this tutorial, we ignore the "manual" flag on the
# tasks. In practice, you probably don't want to do that.
workflow.complete_all(halt_on_manual=False)
workflow.run_all(halt_on_manual=False)
# Alternatively, this is what a UI would do for a manual task.
#workflow.complete_task_from_id(...)

View File

@ -21,7 +21,10 @@ setup(name='SpiffWorkflow',
author_email='dan@sartography.com',
license='lGPLv2',
packages=find_packages(exclude=['tests', 'tests.*']),
package_data={'SpiffWorkflow.bpmn.parser.schema': ['*.xsd']},
package_data={
'SpiffWorkflow.bpmn.parser': ['schema/*.xsd'],
'SpiffWorkflow.dmn.parser': ['schema/*.xsd'],
},
install_requires=['configparser', 'lxml', 'celery',
# required for python 3.7 - https://stackoverflow.com/a/73932581
'importlib-metadata<5.0; python_version <= "3.7"'],

View File

@ -1,103 +0,0 @@
# -*- coding: utf-8 -*-
from builtins import object
import sys
import unittest
import os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
from lxml import etree
from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec
from SpiffWorkflow.task import Task
from SpiffWorkflow.serializer.prettyxml import XmlSerializer
from tests.SpiffWorkflow.util import run_workflow
class WorkflowTestData(object):
def __init__(self, filename, spec, path, data):
self.filename = filename
self.spec = spec
self.path = path
self.data = data
class PatternTest(unittest.TestCase):
maxDiff = None
def setUp(self):
Task.id_pool = 0
Task.thread_id_pool = 0
self.xml_path = ['data/spiff/control-flow',
'data/spiff/data',
'data/spiff/resource',
'data/spiff']
self.workflows = []
for basedir in self.xml_path:
dirname = os.path.join(os.path.dirname(__file__), basedir)
for filename in os.listdir(dirname):
if not filename.endswith(('.xml', '.py')):
continue
if filename.endswith('__.py'):
continue
filename = os.path.join(dirname, filename)
self.load_workflow_spec(filename)
def load_workflow_spec(self, filename):
# Load the .path file.
path_file = os.path.splitext(filename)[0] + '.path'
if os.path.exists(path_file):
with open(path_file) as fp:
expected_path = fp.read()
else:
expected_path = None
# Load the .data file.
data_file = os.path.splitext(filename)[0] + '.data'
if os.path.exists(data_file):
with open(data_file) as fp:
expected_data = fp.read()
else:
expected_data = None
# Test patterns that are defined in XML format.
if filename.endswith('.xml'):
with open(filename) as fp:
xml = etree.parse(fp).getroot()
serializer = XmlSerializer()
wf_spec = WorkflowSpec.deserialize(
serializer, xml, filename=filename)
# Test patterns that are defined in Python.
elif filename.endswith('.py'):
with open(filename) as fp:
code = compile(fp.read(), filename, 'exec')
thedict = {}
result = eval(code, thedict)
wf_spec = thedict['TestWorkflowSpec']()
else:
raise Exception('unsuported specification format', filename)
test_data = WorkflowTestData(
filename, wf_spec, expected_path, expected_data)
self.workflows.append(test_data)
def testWorkflowSpec(self):
for test in self.workflows:
print(test.filename)
run_workflow(self, test.spec, test.path, test.data)
def suite():
return unittest.TestLoader().loadTestsFromTestCase(PatternTest)
if __name__ == '__main__':
if len(sys.argv) == 2:
test = PatternTest('run_pattern')
test.setUp()
test.run_pattern(sys.argv[1])
sys.exit(0)
unittest.TextTestRunner(verbosity=2).run(suite())

View File

@ -2,7 +2,7 @@
import unittest
from SpiffWorkflow.bpmn.workflow import BpmnWorkflow
from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase
from .BpmnWorkflowTestCase import BpmnWorkflowTestCase
__author__ = 'matth'

View File

@ -1,10 +1,7 @@
# -*- coding: utf-8 -*-
from builtins import range
import unittest
import logging
from SpiffWorkflow.task import TaskState
from SpiffWorkflow.bpmn.workflow import BpmnWorkflow
from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase
__author__ = 'matth'
@ -28,13 +25,9 @@ class BaseParallelTestCase(BpmnWorkflowTestCase):
"Doing step '%s' (with choice='%s')", s, choice)
else:
logging.info("Doing step '%s'", s)
# logging.debug(self.workflow.get_dump())
self.do_next_named_step(
s, choice=choice, only_one_instance=only_one_instance)
self.do_next_named_step(s, choice=choice, only_one_instance=only_one_instance)
self.workflow.do_engine_steps()
if save_restore:
# logging.debug("Before SaveRestore: \n%s" %
# self.workflow.get_dump())
self.save_restore()
self.workflow.do_engine_steps()

View File

@ -34,7 +34,7 @@ class TestUserTask(UserTask):
def do_choice(self, task, choice):
task.set_data(choice=choice)
task.complete()
task.run()
class TestExclusiveGatewayParser(ConditionalGatewayParser):

View File

@ -64,7 +64,7 @@ class BpmnWorkflowTestCase(unittest.TestCase):
def switch_workflow(p):
for task_id, sp in p.workflow._get_outermost_workflow().subprocesses.items():
if p in sp.get_tasks(workflow=sp):
return p.workflow.get_task(task_id)
return p.workflow.get_task_from_id(task_id)
def is_match(t):
if not (t.task_spec.name == step_name_path[-1] or t.task_spec.description == step_name_path[-1]):
@ -116,7 +116,7 @@ class BpmnWorkflowTestCase(unittest.TestCase):
if set_attribs:
tasks[0].set_data(**set_attribs)
tasks[0].complete()
tasks[0].run()
def save_restore(self):

View File

@ -6,7 +6,7 @@ from SpiffWorkflow.bpmn.PythonScriptEngine import PythonScriptEngine
from SpiffWorkflow.bpmn.workflow import BpmnWorkflow
from SpiffWorkflow.exceptions import WorkflowTaskException
from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase
from .BpmnWorkflowTestCase import BpmnWorkflowTestCase
__author__ = 'kellym'

View File

@ -82,7 +82,7 @@ class CollaborationTest(BpmnWorkflowTestCase):
workflow.do_engine_steps()
for idx, task in enumerate(workflow.get_ready_user_tasks()):
task.data['task_num'] = idx
task.complete()
task.run()
workflow.do_engine_steps()
ready_tasks = workflow.get_ready_user_tasks()
waiting = workflow.get_tasks_from_spec_name('get_response')
@ -94,7 +94,7 @@ class CollaborationTest(BpmnWorkflowTestCase):
# Now copy the task_num that was sent into a new variable
for task in ready_tasks:
task.data.update(init_id=task.data['task_num'])
task.complete()
task.run()
workflow.do_engine_steps()
# If the messages were routed properly, the id should match
for task in workflow.get_tasks_from_spec_name('subprocess_end'):
@ -108,7 +108,7 @@ class CollaborationTest(BpmnWorkflowTestCase):
workflow.do_engine_steps()
for idx, task in enumerate(workflow.get_ready_user_tasks()):
task.data['task_num'] = idx
task.complete()
task.run()
workflow.do_engine_steps()
# Two processes should have been started and two corresponding catch events should be waiting
@ -121,12 +121,12 @@ class CollaborationTest(BpmnWorkflowTestCase):
# Now copy the task_num that was sent into a new variable
for task in ready_tasks:
task.data.update(init_id=task.data['task_num'])
task.complete()
task.run()
workflow.do_engine_steps()
# Complete dummy tasks
for task in workflow.get_ready_user_tasks():
task.complete()
task.run()
workflow.do_engine_steps()
# Repeat for the other process, using a different mapped name
@ -136,7 +136,7 @@ class CollaborationTest(BpmnWorkflowTestCase):
self.assertEqual(len(waiting), 2)
for task in ready_tasks:
task.data.update(subprocess=task.data['task_num'])
task.complete()
task.run()
workflow.do_engine_steps()
# If the messages were routed properly, the id should match

View File

@ -22,13 +22,13 @@ class DataObjectReferenceTest(BpmnWorkflowTestCase):
# Add the data so that we can advance the workflow
ready_tasks = self.workflow.get_ready_user_tasks()
ready_tasks[0].data = { 'obj_1': 'hello' }
ready_tasks[0].complete()
ready_tasks[0].run()
# Remove the data before advancing
ready_tasks = self.workflow.get_ready_user_tasks()
self.workflow.data.pop('obj_1')
with self.assertRaises(WorkflowDataException) as exc:
ready_tasks[0].complete()
ready_tasks[0].run()
self.assertEqual(exc.data_output.name, 'obj_1')
def testMissingDataOutput(self):
@ -37,7 +37,7 @@ class DataObjectReferenceTest(BpmnWorkflowTestCase):
self.workflow.do_engine_steps()
ready_tasks = self.workflow.get_ready_user_tasks()
with self.assertRaises(WorkflowDataException) as exc:
ready_tasks[0].complete()
ready_tasks[0].run()
self.assertEqual(exc.data_output.name, 'obj_1')
def actual_test(self, save_restore):
@ -48,7 +48,7 @@ class DataObjectReferenceTest(BpmnWorkflowTestCase):
# Set up the data
ready_tasks = self.workflow.get_ready_user_tasks()
ready_tasks[0].data = { 'obj_1': 'hello' }
ready_tasks[0].complete()
ready_tasks[0].run()
# After task completion, obj_1 should be copied out of the task into the workflow
self.assertNotIn('obj_1', ready_tasks[0].data)
self.assertIn('obj_1', self.workflow.data)
@ -59,14 +59,14 @@ class DataObjectReferenceTest(BpmnWorkflowTestCase):
# Set a value for obj_1 in the task data again
ready_tasks = self.workflow.get_ready_user_tasks()
ready_tasks[0].data = { 'obj_1': 'hello again' }
ready_tasks[0].complete()
ready_tasks[0].run()
# Check to make sure we use the workflow value instead of the value we set
ready_tasks = self.workflow.get_ready_user_tasks()
self.assertEqual(ready_tasks[0].data['obj_1'], 'hello')
# Modify the value in the task
ready_tasks[0].data = { 'obj_1': 'hello again' }
ready_tasks[0].complete()
ready_tasks[0].run()
# We did not set an output data reference so obj_1 should remain unchanged in the workflow data
# and be removed from the task data
self.assertNotIn('obj_1', ready_tasks[0].data)
@ -77,7 +77,7 @@ class DataObjectReferenceTest(BpmnWorkflowTestCase):
ready_tasks = self.workflow.get_ready_user_tasks()
self.assertEqual(ready_tasks[0].data['obj_1'], 'hello')
ready_tasks[0].data['obj_1'] = 'hello again'
ready_tasks[0].complete()
ready_tasks[0].run()
self.workflow.do_engine_steps()
sp = self.workflow.get_tasks_from_spec_name('subprocess')[0]
# It was copied out

View File

@ -76,7 +76,7 @@ class CallActivityDataTest(BpmnWorkflowTestCase):
waiting = self.workflow.get_tasks(TaskState.WAITING)
while len(waiting) == 0:
next_task = self.workflow.get_tasks(TaskState.READY)[0]
next_task.complete()
next_task.run()
waiting = self.workflow.get_tasks(TaskState.WAITING)
def complete_subprocess(self):
@ -84,7 +84,7 @@ class CallActivityDataTest(BpmnWorkflowTestCase):
waiting = self.workflow.get_tasks(TaskState.WAITING)
while len(waiting) > 0:
next_task = self.workflow.get_tasks(TaskState.READY)[0]
next_task.complete()
next_task.run()
waiting = self.workflow.get_tasks(TaskState.WAITING)
@ -113,7 +113,7 @@ class IOSpecOnTaskTest(BpmnWorkflowTestCase):
task = self.workflow.get_tasks_from_spec_name('any_task')[0]
task.data.update({'out_1': 1})
with self.assertRaises(WorkflowDataException) as exc:
task.complete()
task.run()
self.assertEqual(exc.exception.data_output.name, 'out_2')
def actual_test(self, save_restore=False):
@ -124,6 +124,6 @@ class IOSpecOnTaskTest(BpmnWorkflowTestCase):
task = self.workflow.get_tasks_from_spec_name('any_task')[0]
self.assertDictEqual(task.data, {'in_1': 1, 'in_2': 'hello world'})
task.data.update({'out_1': 1, 'out_2': 'bye', 'extra': True})
task.complete()
task.run()
self.workflow.do_engine_steps()
self.assertDictEqual(self.workflow.last_task.data, {'out_1': 1, 'out_2': 'bye'})

View File

@ -36,4 +36,4 @@ class InclusiveGatewayTest(BpmnWorkflowTestCase):
def set_data(self, value):
task = self.workflow.get_ready_user_tasks()[0]
task.data = value
task.complete()
task.run()

View File

@ -26,7 +26,7 @@ class BaseTestCase(BpmnWorkflowTestCase):
self.assertEqual(task.task_spec.name, 'any_task [child]')
self.assertIn('input_item', task.data)
task.data['output_item'] = task.data['input_item'] * 2
task.complete()
task.run()
if save_restore:
self.save_restore()
ready_tasks = self.workflow.get_ready_user_tasks()
@ -47,7 +47,7 @@ class BaseTestCase(BpmnWorkflowTestCase):
self.assertEqual(len(ready_tasks), 3)
task = [t for t in ready_tasks if t.data['input_item'] == 2][0]
task.data['output_item'] = task.data['input_item'] * 2
task.complete()
task.run()
self.workflow.do_engine_steps()
self.workflow.refresh_waiting_tasks()

View File

@ -20,7 +20,7 @@ class ParallelOrderTest(BpmnWorkflowTestCase):
self.workflow.do_engine_steps()
self.assertFalse(self.workflow.is_completed())
self.assertEquals(4, len(self.workflow.get_ready_user_tasks()))
self.assertEqual(4, len(self.workflow.get_ready_user_tasks()))
tasks = self.workflow.get_ready_user_tasks()
self.assertEquals("Task 1", tasks[0].get_description())
self.assertEquals("Task 2", tasks[1].get_description())

View File

@ -51,7 +51,7 @@ class ParallelThroughSameTaskTest(BpmnWorkflowTestCase):
self.assertEqual(2, len(ready_tasks))
self.assertEqual(
'Repeated Task', ready_tasks[0].task_spec.description)
ready_tasks[0].complete()
ready_tasks[0].run()
self.workflow.do_engine_steps()
# The inclusive gateway allows us through here, because there is no route for the other thread
# that doesn't use the same sequence flow
@ -82,7 +82,7 @@ class ParallelThroughSameTaskTest(BpmnWorkflowTestCase):
self.assertEqual(2, len(ready_tasks))
self.assertEqual(
'Repeated Task', ready_tasks[0].task_spec.description)
ready_tasks[0].complete()
ready_tasks[0].run()
self.workflow.do_engine_steps()
self.save_restore()
# The inclusive gateway allows us through here, because there is no route for the other thread

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.complete_task_from_id(top_level_task.id)
self.workflow.run_task_from_id(top_level_task.id)
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.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
task = self.workflow.get_ready_user_tasks()[0]
self.assertEqual(task.get_name(),'SubTask2')
self.workflow.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
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,19 @@ class ResetSubProcessTest(BpmnWorkflowTestCase):
self.reload_save_restore()
task = self.workflow.get_ready_user_tasks()[0]
self.assertEqual(task.get_name(),'Task1')
self.workflow.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
task = self.workflow.get_ready_user_tasks()[0]
self.assertEqual(task.get_name(),'Subtask2')
self.workflow.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
task = self.workflow.get_ready_user_tasks()[0]
self.assertEqual(task.get_name(),'Subtask2A')
self.workflow.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
task = self.workflow.get_ready_user_tasks()[0]
self.assertEqual(task.get_name(),'Task2')
self.workflow.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
self.assertTrue(self.workflow.is_completed())

View File

@ -1,28 +0,0 @@
from SpiffWorkflow.bpmn.workflow import BpmnWorkflow
from SpiffWorkflow.task import TaskState
from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase
class ResetTimerTest(BpmnWorkflowTestCase):
def test_timer(self):
spec, subprocess = self.load_workflow_spec('reset_timer.bpmn', 'main')
self.workflow = BpmnWorkflow(spec, subprocess)
self.workflow.do_engine_steps()
task_1 = self.workflow.get_tasks_from_spec_name('task_1')[0]
timer = self.workflow.get_tasks_from_spec_name('timer')[0]
original_timer = timer.internal_data.get('event_value')
# This returns us to the task
task_1.data['modify'] = True
task_1.complete()
self.workflow.do_engine_steps()
# The timer should be waiting and the time should have been updated
self.assertEqual(task_1.state, TaskState.READY)
self.assertEqual(timer.state, TaskState.WAITING)
self.assertGreater(timer.internal_data.get('event_value'), original_timer)
task_1.data['modify'] = False
task_1.complete()
self.workflow.do_engine_steps()
self.assertEqual(timer.state, TaskState.CANCELLED)
self.assertTrue(self.workflow.is_completed())

View File

@ -27,7 +27,7 @@ class BaseTestCase(BpmnWorkflowTestCase):
self.assertEqual(task.task_spec.name, 'any_task [child]')
self.assertIn('input_item', task.data)
task.data['output_item'] = task.data['input_item'] * 2
task.complete()
task.run()
if save_restore:
self.save_restore()
ready_tasks = self.workflow.get_ready_user_tasks()
@ -54,7 +54,7 @@ class BaseTestCase(BpmnWorkflowTestCase):
self.assertEqual(ready.task_spec.name, 'any_task [child]')
self.assertIn('input_item', ready.data)
ready.data['output_item'] = ready.data['input_item'] * 2
ready.complete()
ready.run()
self.workflow.do_engine_steps()
self.workflow.refresh_waiting_tasks()
ready_tasks = self.workflow.get_ready_user_tasks()

View File

@ -21,7 +21,7 @@ class StandardLoopTest(BpmnWorkflowTestCase):
ready_tasks = self.workflow.get_ready_user_tasks()
self.assertEqual(len(ready_tasks), 1)
ready_tasks[0].data[str(idx)] = True
ready_tasks[0].complete()
ready_tasks[0].run()
self.workflow.do_engine_steps()
self.assertTrue(self.workflow.is_completed())
@ -36,7 +36,7 @@ class StandardLoopTest(BpmnWorkflowTestCase):
ready_tasks = self.workflow.get_ready_user_tasks()
self.assertEqual(len(ready_tasks), 1)
ready_tasks[0].data['done'] = True
ready_tasks[0].complete()
ready_tasks[0].run()
self.workflow.do_engine_steps()
self.assertTrue(self.workflow.is_completed())

View File

@ -35,7 +35,7 @@ class SwimLaneTest(BpmnWorkflowTestCase):
self.assertEqual(0, len(btasks))
task = atasks[0]
self.assertEqual('Activity_A1', task.task_spec.name)
self.workflow.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
atasks = self.workflow.get_ready_user_tasks(lane="A")
btasks = self.workflow.get_ready_user_tasks(lane="B")
@ -44,10 +44,10 @@ class SwimLaneTest(BpmnWorkflowTestCase):
# Complete the gateway and the two tasks in B Lane
btasks[0].data = {'NeedClarification': False}
self.workflow.complete_task_from_id(btasks[0].id)
self.workflow.run_task_from_id(btasks[0].id)
self.workflow.do_engine_steps()
btasks = self.workflow.get_ready_user_tasks(lane="B")
self.workflow.complete_task_from_id(btasks[0].id)
self.workflow.run_task_from_id(btasks[0].id)
self.workflow.do_engine_steps()
# Assert we are in lane C
@ -56,7 +56,7 @@ class SwimLaneTest(BpmnWorkflowTestCase):
self.assertEqual(tasks[0].task_spec.lane, "C")
# Step into the sub-process, assure that is also in lane C
self.workflow.complete_task_from_id(tasks[0].id)
self.workflow.run_task_from_id(tasks[0].id)
self.workflow.do_engine_steps()
tasks = self.workflow.get_ready_user_tasks()
self.assertEqual("SubProcessTask", tasks[0].task_spec.description)

View File

@ -1,86 +0,0 @@
# -*- coding: utf-8 -*-
import datetime
import unittest
from SpiffWorkflow.bpmn.PythonScriptEngine import PythonScriptEngine
from SpiffWorkflow.bpmn.PythonScriptEngineEnvironment import TaskDataEnvironment
from SpiffWorkflow.bpmn.workflow import BpmnWorkflow
from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase
__author__ = 'sartography'
class CustomScriptEngine(PythonScriptEngine):
"""This is a custom script processor that can be easily injected into Spiff Workflow.
It will execute python code read in from the bpmn. It will also make any scripts in the
scripts directory available for execution. """
def __init__(self):
environment = TaskDataEnvironment({
'timedelta': datetime.timedelta,
})
super().__init__(environment=environment)
class TooManyLoopsTest(BpmnWorkflowTestCase):
"""Looping back around many times would cause the tree of tasks to grow
for each loop, doing this a 100 or 1000 times would cause the system to
run fail in various ways. This assures that is no longer the case."""
def testRunThroughHappy(self):
self.actual_test(save_restore=False)
def testThroughSaveRestore(self):
self.actual_test(save_restore=True)
def actual_test(self,save_restore = False):
spec, subprocesses = self.load_workflow_spec('too_many_loops*.bpmn', 'loops')
self.workflow = BpmnWorkflow(spec, subprocesses, script_engine=CustomScriptEngine())
counter = 0
data = {}
while not self.workflow.is_completed():
self.workflow.do_engine_steps()
self.workflow.refresh_waiting_tasks()
if (self.workflow.last_task.data != data):
data = self.workflow.last_task.data
counter += 1 # There is a 10 millisecond wait task.
if save_restore:
self.save_restore()
self.workflow.script_engine = CustomScriptEngine()
self.assertEqual(20, self.workflow.last_task.data['counter'])
def test_with_sub_process(self):
# Found an issue where looping back would fail when it happens
# right after a sub-process. So assuring this is fixed.
counter = 0
spec, subprocesses = self.load_workflow_spec('too_many_loops_sub_process.bpmn', 'loops_sub')
self.workflow = BpmnWorkflow(spec, subprocesses, script_engine=CustomScriptEngine())
data = {}
while not self.workflow.is_completed():
self.workflow.do_engine_steps()
self.workflow.refresh_waiting_tasks()
if (self.workflow.last_task.data != data):
data = self.workflow.last_task.data
counter += 1 # There is a 10 millisecond wait task.
# self.save_restore()
self.assertEqual(20, self.workflow.last_task.data['counter'])
# One less, because we don't go back through once the first counter
# hits 20.
self.assertEqual(19, self.workflow.last_task.data['counter2'])
def test_with_two_call_activities(self):
spec, subprocess = self.load_workflow_spec('sub_in_loop*.bpmn', 'main')
self.workflow = BpmnWorkflow(spec, subprocess, script_engine=CustomScriptEngine())
self.workflow.do_engine_steps()
for loop in range(3):
ready = self.workflow.get_ready_user_tasks()
ready[0].data = { 'done': True if loop == 3 else False }
ready[0].complete()
self.workflow.refresh_waiting_tasks()
self.workflow.do_engine_steps()
self.save_restore()
self.workflow.script_engine = CustomScriptEngine()
def suite():
return unittest.TestLoader().loadTestsFromTestCase(TooManyLoopsTest)
if __name__ == '__main__':
unittest.TextTestRunner(verbosity=2).run(suite())

View File

@ -1,291 +1,303 @@
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" xmlns:signavio="http://www.signavio.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" exporter="Signavio Process Editor, http://www.signavio.com" exporterVersion="" expressionLanguage="http://www.w3.org/1999/XPath" id="sid-fafc406d-50f2-41f2-b75b-ad652445d52e" targetNamespace="http://www.signavio.com/bpmn20" typeLanguage="http://www.w3.org/2001/XMLSchema" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL http://www.omg.org/spec/BPMN/2.0/20100501/BPMN20.xsd">
<collaboration id="sid-5801c79c-823f-4040-b680-417ef5bcb3a2">
<participant id="sid-B2E5AD50-035A-4CE8-B8A3-B175A6767B00" name="Parallel Looping After Join" processRef="sid-41eb2b6c-08bc-4a61-b38b-5f32052139c5">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffff"/>
</extensionElements>
</participant>
</collaboration>
<process id="sid-41eb2b6c-08bc-4a61-b38b-5f32052139c5" isClosed="false" isExecutable="false" name="Parallel Looping After Join" processType="None">
<laneSet id="sid-127ca06b-aba8-45aa-bd8a-7be70ec94b2c">
<lane id="sid-72009BCE-46B4-4B4B-AEAE-1E7199522142" name="Tester">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue=""/>
</extensionElements>
<flowNodeRef>sid-B33EE043-AB93-4343-A1D4-7B267E2DAFBE</flowNodeRef>
<flowNodeRef>sid-349F8C0C-45EA-489C-84DD-1D944F48D778</flowNodeRef>
<flowNodeRef>sid-57463471-693A-42A2-9EC6-6460BEDECA86</flowNodeRef>
<flowNodeRef>sid-CA089240-802A-4C32-9130-FB1A33DDCCC3</flowNodeRef>
<flowNodeRef>sid-E976FBC2-266E-420F-8D4D-C8FBC6199090</flowNodeRef>
<flowNodeRef>sid-F3A979E3-F586-4807-8223-1FAB5A5647B0</flowNodeRef>
<flowNodeRef>sid-51816945-79BF-47F9-BA3C-E95ABAE3D1DB</flowNodeRef>
<flowNodeRef>sid-4F7F3AA6-4E8E-458D-BBEF-E03FC0646897</flowNodeRef>
<flowNodeRef>sid-ABD788A3-CD57-4280-A22A-260B3AEEE138</flowNodeRef>
<flowNodeRef>sid-E7B8898A-0D14-4E98-B3D7-736B94EE3FA7</flowNodeRef>
<flowNodeRef>sid-A1609BD5-1E4A-47AE-8648-1DD41D1B1D58</flowNodeRef>
<flowNodeRef>sid-1946C635-7886-4687-844F-C644FA6222B8</flowNodeRef>
<flowNodeRef>sid-4C3B3C16-91DB-43E3-A816-FFEE572E61E1</flowNodeRef>
<flowNodeRef>sid-55C018B8-C073-4292-9ED0-79BDE50E7498</flowNodeRef>
<flowNodeRef>sid-E7904BFA-1F17-478E-91C9-C8A5B64190C9</flowNodeRef>
</lane>
</laneSet>
<startEvent id="sid-B33EE043-AB93-4343-A1D4-7B267E2DAFBE" name="">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffff"/>
</extensionElements>
<outgoing>sid-F3994F51-FE54-4910-A1F4-E5895AA1A612</outgoing>
</startEvent>
<parallelGateway gatewayDirection="Diverging" id="sid-349F8C0C-45EA-489C-84DD-1D944F48D778" name="First Split">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffff"/>
</extensionElements>
<incoming>sid-3E0EBE59-75C8-465C-90CC-197CE808A96E</incoming>
<outgoing>sid-7E15C71B-DE9E-4788-B140-A647C99FDC94</outgoing>
<outgoing>sid-B6E22A74-A691-453A-A789-B9F8AF787D7C</outgoing>
</parallelGateway>
<task completionQuantity="1" id="sid-57463471-693A-42A2-9EC6-6460BEDECA86" isForCompensation="false" name="1" startQuantity="1">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffcc"/>
</extensionElements>
<incoming>sid-7E15C71B-DE9E-4788-B140-A647C99FDC94</incoming>
<outgoing>sid-607CB05E-8762-41B6-AD43-C3970661A99D</outgoing>
</task>
<task completionQuantity="1" id="sid-CA089240-802A-4C32-9130-FB1A33DDCCC3" isForCompensation="false" name="2" startQuantity="1">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffcc"/>
</extensionElements>
<incoming>sid-B6E22A74-A691-453A-A789-B9F8AF787D7C</incoming>
<outgoing>sid-CAEAD081-6E73-4C98-8656-C67DA18F5140</outgoing>
</task>
<parallelGateway gatewayDirection="Converging" id="sid-E976FBC2-266E-420F-8D4D-C8FBC6199090" name="Join of First Split">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffff"/>
</extensionElements>
<incoming>sid-231F8A51-752F-4CB3-8FD1-23D153238344</incoming>
<incoming>sid-607CB05E-8762-41B6-AD43-C3970661A99D</incoming>
<outgoing>sid-0895E09C-077C-4D12-8C11-31F28CBC7740</outgoing>
</parallelGateway>
<task completionQuantity="1" id="sid-F3A979E3-F586-4807-8223-1FAB5A5647B0" isForCompensation="false" name="Retry?" startQuantity="1">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffcc"/>
</extensionElements>
<incoming>sid-0895E09C-077C-4D12-8C11-31F28CBC7740</incoming>
<outgoing>sid-2668AC98-39E4-4B12-9052-930528086CAC</outgoing>
</task>
<endEvent id="sid-51816945-79BF-47F9-BA3C-E95ABAE3D1DB" name="">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffff"/>
</extensionElements>
<incoming>sid-F6160C0E-216C-4D72-98D1-CC5549327D55</incoming>
</endEvent>
<parallelGateway gatewayDirection="Diverging" id="sid-4F7F3AA6-4E8E-458D-BBEF-E03FC0646897" name="Second Split">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffff"/>
</extensionElements>
<incoming>sid-CAEAD081-6E73-4C98-8656-C67DA18F5140</incoming>
<outgoing>sid-918C653D-0960-4223-9C28-78114F238BCC</outgoing>
<outgoing>sid-FD82C2A6-7C54-4890-901E-A7E864F7605C</outgoing>
</parallelGateway>
<task completionQuantity="1" id="sid-ABD788A3-CD57-4280-A22A-260B3AEEE138" isForCompensation="false" name="2A" startQuantity="1">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffcc"/>
</extensionElements>
<incoming>sid-918C653D-0960-4223-9C28-78114F238BCC</incoming>
<outgoing>sid-961AF51C-9935-410E-AAA4-105B19186F5E</outgoing>
</task>
<task completionQuantity="1" id="sid-E7B8898A-0D14-4E98-B3D7-736B94EE3FA7" isForCompensation="false" name="2B" startQuantity="1">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffcc"/>
</extensionElements>
<incoming>sid-FD82C2A6-7C54-4890-901E-A7E864F7605C</incoming>
<outgoing>sid-47947925-21CD-46FF-8D3F-294B235AA4CF</outgoing>
</task>
<parallelGateway gatewayDirection="Converging" id="sid-A1609BD5-1E4A-47AE-8648-1DD41D1B1D58" name="Join of Second Split">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffff"/>
</extensionElements>
<incoming>sid-961AF51C-9935-410E-AAA4-105B19186F5E</incoming>
<incoming>sid-47947925-21CD-46FF-8D3F-294B235AA4CF</incoming>
<outgoing>sid-AFA38469-CD5C-42A2-9473-2EAEBA61F0C0</outgoing>
</parallelGateway>
<task completionQuantity="1" id="sid-1946C635-7886-4687-844F-C644FA6222B8" isForCompensation="false" name="2 Done" startQuantity="1">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffcc"/>
</extensionElements>
<incoming>sid-AFA38469-CD5C-42A2-9473-2EAEBA61F0C0</incoming>
<outgoing>sid-231F8A51-752F-4CB3-8FD1-23D153238344</outgoing>
</task>
<exclusiveGateway gatewayDirection="Diverging" id="sid-4C3B3C16-91DB-43E3-A816-FFEE572E61E1" name="">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffff"/>
</extensionElements>
<incoming>sid-2668AC98-39E4-4B12-9052-930528086CAC</incoming>
<outgoing>sid-08D6385B-C6BB-45FC-A6BD-2369F392868D</outgoing>
<outgoing>sid-41205B5D-4DBA-4155-A0EE-7D71CE9AA459</outgoing>
</exclusiveGateway>
<task completionQuantity="1" id="sid-55C018B8-C073-4292-9ED0-79BDE50E7498" isForCompensation="false" name="Done" startQuantity="1">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffcc"/>
</extensionElements>
<incoming>sid-08D6385B-C6BB-45FC-A6BD-2369F392868D</incoming>
<outgoing>sid-F6160C0E-216C-4D72-98D1-CC5549327D55</outgoing>
</task>
<task completionQuantity="1" id="sid-E7904BFA-1F17-478E-91C9-C8A5B64190C9" isForCompensation="false" name="Go" startQuantity="1">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffcc"/>
</extensionElements>
<incoming>sid-41205B5D-4DBA-4155-A0EE-7D71CE9AA459</incoming>
<incoming>sid-F3994F51-FE54-4910-A1F4-E5895AA1A612</incoming>
<outgoing>sid-3E0EBE59-75C8-465C-90CC-197CE808A96E</outgoing>
</task>
<sequenceFlow id="sid-7E15C71B-DE9E-4788-B140-A647C99FDC94" name="" sourceRef="sid-349F8C0C-45EA-489C-84DD-1D944F48D778" targetRef="sid-57463471-693A-42A2-9EC6-6460BEDECA86"/>
<sequenceFlow id="sid-B6E22A74-A691-453A-A789-B9F8AF787D7C" name="" sourceRef="sid-349F8C0C-45EA-489C-84DD-1D944F48D778" targetRef="sid-CA089240-802A-4C32-9130-FB1A33DDCCC3"/>
<sequenceFlow id="sid-0895E09C-077C-4D12-8C11-31F28CBC7740" name="" sourceRef="sid-E976FBC2-266E-420F-8D4D-C8FBC6199090" targetRef="sid-F3A979E3-F586-4807-8223-1FAB5A5647B0"/>
<sequenceFlow id="sid-CAEAD081-6E73-4C98-8656-C67DA18F5140" name="" sourceRef="sid-CA089240-802A-4C32-9130-FB1A33DDCCC3" targetRef="sid-4F7F3AA6-4E8E-458D-BBEF-E03FC0646897"/>
<sequenceFlow id="sid-918C653D-0960-4223-9C28-78114F238BCC" name="" sourceRef="sid-4F7F3AA6-4E8E-458D-BBEF-E03FC0646897" targetRef="sid-ABD788A3-CD57-4280-A22A-260B3AEEE138"/>
<sequenceFlow id="sid-FD82C2A6-7C54-4890-901E-A7E864F7605C" name="" sourceRef="sid-4F7F3AA6-4E8E-458D-BBEF-E03FC0646897" targetRef="sid-E7B8898A-0D14-4E98-B3D7-736B94EE3FA7"/>
<sequenceFlow id="sid-961AF51C-9935-410E-AAA4-105B19186F5E" name="" sourceRef="sid-ABD788A3-CD57-4280-A22A-260B3AEEE138" targetRef="sid-A1609BD5-1E4A-47AE-8648-1DD41D1B1D58"/>
<sequenceFlow id="sid-47947925-21CD-46FF-8D3F-294B235AA4CF" name="" sourceRef="sid-E7B8898A-0D14-4E98-B3D7-736B94EE3FA7" targetRef="sid-A1609BD5-1E4A-47AE-8648-1DD41D1B1D58"/>
<sequenceFlow id="sid-AFA38469-CD5C-42A2-9473-2EAEBA61F0C0" name="" sourceRef="sid-A1609BD5-1E4A-47AE-8648-1DD41D1B1D58" targetRef="sid-1946C635-7886-4687-844F-C644FA6222B8"/>
<sequenceFlow id="sid-231F8A51-752F-4CB3-8FD1-23D153238344" name="" sourceRef="sid-1946C635-7886-4687-844F-C644FA6222B8" targetRef="sid-E976FBC2-266E-420F-8D4D-C8FBC6199090"/>
<sequenceFlow id="sid-607CB05E-8762-41B6-AD43-C3970661A99D" name="" sourceRef="sid-57463471-693A-42A2-9EC6-6460BEDECA86" targetRef="sid-E976FBC2-266E-420F-8D4D-C8FBC6199090"/>
<sequenceFlow id="sid-2668AC98-39E4-4B12-9052-930528086CAC" name="" sourceRef="sid-F3A979E3-F586-4807-8223-1FAB5A5647B0" targetRef="sid-4C3B3C16-91DB-43E3-A816-FFEE572E61E1"/>
<sequenceFlow id="sid-08D6385B-C6BB-45FC-A6BD-2369F392868D" name="No" sourceRef="sid-4C3B3C16-91DB-43E3-A816-FFEE572E61E1" targetRef="sid-55C018B8-C073-4292-9ED0-79BDE50E7498"/>
<sequenceFlow id="sid-F6160C0E-216C-4D72-98D1-CC5549327D55" name="" sourceRef="sid-55C018B8-C073-4292-9ED0-79BDE50E7498" targetRef="sid-51816945-79BF-47F9-BA3C-E95ABAE3D1DB"/>
<sequenceFlow id="sid-41205B5D-4DBA-4155-A0EE-7D71CE9AA459" name="Yes" sourceRef="sid-4C3B3C16-91DB-43E3-A816-FFEE572E61E1" targetRef="sid-E7904BFA-1F17-478E-91C9-C8A5B64190C9"/>
<sequenceFlow id="sid-3E0EBE59-75C8-465C-90CC-197CE808A96E" name="" sourceRef="sid-E7904BFA-1F17-478E-91C9-C8A5B64190C9" targetRef="sid-349F8C0C-45EA-489C-84DD-1D944F48D778"/>
<sequenceFlow id="sid-F3994F51-FE54-4910-A1F4-E5895AA1A612" name="" sourceRef="sid-B33EE043-AB93-4343-A1D4-7B267E2DAFBE" targetRef="sid-E7904BFA-1F17-478E-91C9-C8A5B64190C9"/>
</process>
<bpmndi:BPMNDiagram id="sid-162a2324-4820-489a-9df8-04591b6b429a">
<bpmndi:BPMNPlane bpmnElement="sid-5801c79c-823f-4040-b680-417ef5bcb3a2" id="sid-4c9e28b7-9050-4a64-8a52-634f8f2febc3">
<bpmndi:BPMNShape bpmnElement="sid-B2E5AD50-035A-4CE8-B8A3-B175A6767B00" id="sid-B2E5AD50-035A-4CE8-B8A3-B175A6767B00_gui" isHorizontal="true">
<omgdc:Bounds height="619.0" width="794.0" x="120.0" y="90.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="sid-72009BCE-46B4-4B4B-AEAE-1E7199522142" id="sid-72009BCE-46B4-4B4B-AEAE-1E7199522142_gui" isHorizontal="true">
<omgdc:Bounds height="619.0" width="764.0" x="150.0" y="90.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="sid-B33EE043-AB93-4343-A1D4-7B267E2DAFBE" id="sid-B33EE043-AB93-4343-A1D4-7B267E2DAFBE_gui">
<omgdc:Bounds height="30.0" width="30.0" x="190.0" y="122.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="sid-349F8C0C-45EA-489C-84DD-1D944F48D778" id="sid-349F8C0C-45EA-489C-84DD-1D944F48D778_gui">
<omgdc:Bounds height="40.0" width="40.0" x="374.0" y="180.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="sid-57463471-693A-42A2-9EC6-6460BEDECA86" id="sid-57463471-693A-42A2-9EC6-6460BEDECA86_gui">
<omgdc:Bounds height="80.0" width="100.0" x="510.0" y="214.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="sid-CA089240-802A-4C32-9130-FB1A33DDCCC3" id="sid-CA089240-802A-4C32-9130-FB1A33DDCCC3_gui">
<omgdc:Bounds height="80.0" width="100.0" x="231.0" y="214.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="sid-E976FBC2-266E-420F-8D4D-C8FBC6199090" id="sid-E976FBC2-266E-420F-8D4D-C8FBC6199090_gui">
<omgdc:Bounds height="40.0" width="40.0" x="540.0" y="405.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="sid-F3A979E3-F586-4807-8223-1FAB5A5647B0" id="sid-F3A979E3-F586-4807-8223-1FAB5A5647B0_gui">
<omgdc:Bounds height="80.0" width="100.0" x="615.0" y="385.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="sid-51816945-79BF-47F9-BA3C-E95ABAE3D1DB" id="sid-51816945-79BF-47F9-BA3C-E95ABAE3D1DB_gui">
<omgdc:Bounds height="28.0" width="28.0" x="780.0" y="630.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="sid-4F7F3AA6-4E8E-458D-BBEF-E03FC0646897" id="sid-4F7F3AA6-4E8E-458D-BBEF-E03FC0646897_gui">
<omgdc:Bounds height="40.0" width="40.0" x="261.0" y="338.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="sid-ABD788A3-CD57-4280-A22A-260B3AEEE138" id="sid-ABD788A3-CD57-4280-A22A-260B3AEEE138_gui">
<omgdc:Bounds height="80.0" width="100.0" x="177.0" y="417.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="sid-E7B8898A-0D14-4E98-B3D7-736B94EE3FA7" id="sid-E7B8898A-0D14-4E98-B3D7-736B94EE3FA7_gui">
<omgdc:Bounds height="80.0" width="100.0" x="344.0" y="408.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="sid-A1609BD5-1E4A-47AE-8648-1DD41D1B1D58" id="sid-A1609BD5-1E4A-47AE-8648-1DD41D1B1D58_gui">
<omgdc:Bounds height="40.0" width="40.0" x="285.0" y="555.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="sid-1946C635-7886-4687-844F-C644FA6222B8" id="sid-1946C635-7886-4687-844F-C644FA6222B8_gui">
<omgdc:Bounds height="80.0" width="100.0" x="420.0" y="535.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="sid-4C3B3C16-91DB-43E3-A816-FFEE572E61E1" id="sid-4C3B3C16-91DB-43E3-A816-FFEE572E61E1_gui" isMarkerVisible="true">
<omgdc:Bounds height="40.0" width="40.0" x="774.0" y="405.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="sid-55C018B8-C073-4292-9ED0-79BDE50E7498" id="sid-55C018B8-C073-4292-9ED0-79BDE50E7498_gui">
<omgdc:Bounds height="80.0" width="100.0" x="744.0" y="497.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="sid-E7904BFA-1F17-478E-91C9-C8A5B64190C9" id="sid-E7904BFA-1F17-478E-91C9-C8A5B64190C9_gui">
<omgdc:Bounds height="80.0" width="100.0" x="467.0" y="105.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sid-7E15C71B-DE9E-4788-B140-A647C99FDC94" id="sid-7E15C71B-DE9E-4788-B140-A647C99FDC94_gui">
<omgdi:waypoint x="414.0" y="206.0"/>
<omgdi:waypoint x="510.0" y="238.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-08D6385B-C6BB-45FC-A6BD-2369F392868D" id="sid-08D6385B-C6BB-45FC-A6BD-2369F392868D_gui">
<omgdi:waypoint x="794.0" y="445.0"/>
<omgdi:waypoint x="794.0" y="497.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-F3994F51-FE54-4910-A1F4-E5895AA1A612" id="sid-F3994F51-FE54-4910-A1F4-E5895AA1A612_gui">
<omgdi:waypoint x="220.0" y="137.0"/>
<omgdi:waypoint x="394.0" y="137.0"/>
<omgdi:waypoint x="467.0" y="142.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-231F8A51-752F-4CB3-8FD1-23D153238344" id="sid-231F8A51-752F-4CB3-8FD1-23D153238344_gui">
<omgdi:waypoint x="475.0" y="535.0"/>
<omgdi:waypoint x="491.0" y="425.0"/>
<omgdi:waypoint x="540.0" y="425.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-F6160C0E-216C-4D72-98D1-CC5549327D55" id="sid-F6160C0E-216C-4D72-98D1-CC5549327D55_gui">
<omgdi:waypoint x="794.0" y="577.0"/>
<omgdi:waypoint x="794.0" y="630.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-B6E22A74-A691-453A-A789-B9F8AF787D7C" id="sid-B6E22A74-A691-453A-A789-B9F8AF787D7C_gui">
<omgdi:waypoint x="394.0" y="220.0"/>
<omgdi:waypoint x="394.5" y="254.0"/>
<omgdi:waypoint x="331.0" y="254.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-2668AC98-39E4-4B12-9052-930528086CAC" id="sid-2668AC98-39E4-4B12-9052-930528086CAC_gui">
<omgdi:waypoint x="715.0" y="425.0"/>
<omgdi:waypoint x="774.0" y="425.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-CAEAD081-6E73-4C98-8656-C67DA18F5140" id="sid-CAEAD081-6E73-4C98-8656-C67DA18F5140_gui">
<omgdi:waypoint x="281.0" y="294.0"/>
<omgdi:waypoint x="281.0" y="338.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-918C653D-0960-4223-9C28-78114F238BCC" id="sid-918C653D-0960-4223-9C28-78114F238BCC_gui">
<omgdi:waypoint x="261.0" y="358.0"/>
<omgdi:waypoint x="227.0" y="358.5"/>
<omgdi:waypoint x="227.0" y="417.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-FD82C2A6-7C54-4890-901E-A7E864F7605C" id="sid-FD82C2A6-7C54-4890-901E-A7E864F7605C_gui">
<omgdi:waypoint x="301.0" y="358.0"/>
<omgdi:waypoint x="394.0" y="358.5"/>
<omgdi:waypoint x="394.0" y="408.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-41205B5D-4DBA-4155-A0EE-7D71CE9AA459" id="sid-41205B5D-4DBA-4155-A0EE-7D71CE9AA459_gui">
<omgdi:waypoint x="794.0" y="405.0"/>
<omgdi:waypoint x="794.5" y="145.0"/>
<omgdi:waypoint x="567.0" y="145.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-607CB05E-8762-41B6-AD43-C3970661A99D" id="sid-607CB05E-8762-41B6-AD43-C3970661A99D_gui">
<omgdi:waypoint x="560.0" y="294.0"/>
<omgdi:waypoint x="560.0" y="405.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-AFA38469-CD5C-42A2-9473-2EAEBA61F0C0" id="sid-AFA38469-CD5C-42A2-9473-2EAEBA61F0C0_gui">
<omgdi:waypoint x="325.0" y="575.0"/>
<omgdi:waypoint x="420.0" y="575.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-961AF51C-9935-410E-AAA4-105B19186F5E" id="sid-961AF51C-9935-410E-AAA4-105B19186F5E_gui">
<omgdi:waypoint x="277.0" y="457.0"/>
<omgdi:waypoint x="305.0" y="457.0"/>
<omgdi:waypoint x="305.0" y="555.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-3E0EBE59-75C8-465C-90CC-197CE808A96E" id="sid-3E0EBE59-75C8-465C-90CC-197CE808A96E_gui">
<omgdi:waypoint x="467.0" y="167.0"/>
<omgdi:waypoint x="414.0" y="191.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-0895E09C-077C-4D12-8C11-31F28CBC7740" id="sid-0895E09C-077C-4D12-8C11-31F28CBC7740_gui">
<omgdi:waypoint x="580.0" y="425.0"/>
<omgdi:waypoint x="615.0" y="425.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-47947925-21CD-46FF-8D3F-294B235AA4CF" id="sid-47947925-21CD-46FF-8D3F-294B235AA4CF_gui">
<omgdi:waypoint x="344.0" y="448.0"/>
<omgdi:waypoint x="305.0" y="448.0"/>
<omgdi:waypoint x="305.0" y="555.0"/>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:signavio="http://www.signavio.com" id="sid-fafc406d-50f2-41f2-b75b-ad652445d52e" targetNamespace="http://www.signavio.com/bpmn20" exporter="Camunda Modeler" exporterVersion="4.11.1" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL http://www.omg.org/spec/BPMN/2.0/20100501/BPMN20.xsd">
<collaboration id="sid-5801c79c-823f-4040-b680-417ef5bcb3a2">
<participant id="sid-B2E5AD50-035A-4CE8-B8A3-B175A6767B00" name="Parallel Looping After Join" processRef="sid-41eb2b6c-08bc-4a61-b38b-5f32052139c5">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffff" />
</extensionElements>
</participant>
</collaboration>
<process id="sid-41eb2b6c-08bc-4a61-b38b-5f32052139c5" name="Parallel Looping After Join" processType="None" isClosed="false" isExecutable="false">
<laneSet id="sid-127ca06b-aba8-45aa-bd8a-7be70ec94b2c">
<lane id="sid-72009BCE-46B4-4B4B-AEAE-1E7199522142" name="Tester">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="" />
</extensionElements>
<flowNodeRef>start</flowNodeRef>
<flowNodeRef>first_split</flowNodeRef>
<flowNodeRef>one</flowNodeRef>
<flowNodeRef>two</flowNodeRef>
<flowNodeRef>join_of_first</flowNodeRef>
<flowNodeRef>retry</flowNodeRef>
<flowNodeRef>end</flowNodeRef>
<flowNodeRef>second_split</flowNodeRef>
<flowNodeRef>two_a</flowNodeRef>
<flowNodeRef>two_b</flowNodeRef>
<flowNodeRef>join_of_second_split</flowNodeRef>
<flowNodeRef>two_done</flowNodeRef>
<flowNodeRef>exclusive</flowNodeRef>
<flowNodeRef>done</flowNodeRef>
<flowNodeRef>go</flowNodeRef>
</lane>
</laneSet>
<startEvent id="start" name="">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffff" />
</extensionElements>
<outgoing>sid-F3994F51-FE54-4910-A1F4-E5895AA1A612</outgoing>
</startEvent>
<parallelGateway id="first_split" name="First Split" gatewayDirection="Diverging">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffff" />
</extensionElements>
<incoming>sid-3E0EBE59-75C8-465C-90CC-197CE808A96E</incoming>
<outgoing>sid-7E15C71B-DE9E-4788-B140-A647C99FDC94</outgoing>
<outgoing>sid-B6E22A74-A691-453A-A789-B9F8AF787D7C</outgoing>
</parallelGateway>
<task id="one" name="1">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffcc" />
</extensionElements>
<incoming>sid-7E15C71B-DE9E-4788-B140-A647C99FDC94</incoming>
<outgoing>join_of_first_split</outgoing>
</task>
<task id="two" name="2">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffcc" />
</extensionElements>
<incoming>sid-B6E22A74-A691-453A-A789-B9F8AF787D7C</incoming>
<outgoing>sid-CAEAD081-6E73-4C98-8656-C67DA18F5140</outgoing>
</task>
<parallelGateway id="join_of_first" name="Join of First Split" gatewayDirection="Converging">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffff" />
</extensionElements>
<incoming>sid-231F8A51-752F-4CB3-8FD1-23D153238344</incoming>
<incoming>join_of_first_split</incoming>
<outgoing>sid-0895E09C-077C-4D12-8C11-31F28CBC7740</outgoing>
</parallelGateway>
<task id="retry" name="Retry?">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffcc" />
</extensionElements>
<incoming>sid-0895E09C-077C-4D12-8C11-31F28CBC7740</incoming>
<outgoing>sid-2668AC98-39E4-4B12-9052-930528086CAC</outgoing>
</task>
<endEvent id="end" name="">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffff" />
</extensionElements>
<incoming>sid-F6160C0E-216C-4D72-98D1-CC5549327D55</incoming>
</endEvent>
<parallelGateway id="second_split" name="Second Split" gatewayDirection="Diverging">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffff" />
</extensionElements>
<incoming>sid-CAEAD081-6E73-4C98-8656-C67DA18F5140</incoming>
<outgoing>sid-918C653D-0960-4223-9C28-78114F238BCC</outgoing>
<outgoing>sid-FD82C2A6-7C54-4890-901E-A7E864F7605C</outgoing>
</parallelGateway>
<task id="two_a" name="2A">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffcc" />
</extensionElements>
<incoming>sid-918C653D-0960-4223-9C28-78114F238BCC</incoming>
<outgoing>sid-961AF51C-9935-410E-AAA4-105B19186F5E</outgoing>
</task>
<task id="two_b" name="2B">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffcc" />
</extensionElements>
<incoming>sid-FD82C2A6-7C54-4890-901E-A7E864F7605C</incoming>
<outgoing>sid-47947925-21CD-46FF-8D3F-294B235AA4CF</outgoing>
</task>
<parallelGateway id="join_of_second_split" name="Join of Second Split" gatewayDirection="Converging">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffff" />
</extensionElements>
<incoming>sid-961AF51C-9935-410E-AAA4-105B19186F5E</incoming>
<incoming>sid-47947925-21CD-46FF-8D3F-294B235AA4CF</incoming>
<outgoing>sid-AFA38469-CD5C-42A2-9473-2EAEBA61F0C0</outgoing>
</parallelGateway>
<task id="two_done" name="2 Done">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffcc" />
</extensionElements>
<incoming>sid-AFA38469-CD5C-42A2-9473-2EAEBA61F0C0</incoming>
<outgoing>sid-231F8A51-752F-4CB3-8FD1-23D153238344</outgoing>
</task>
<exclusiveGateway id="exclusive" name="" gatewayDirection="Diverging">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffff" />
</extensionElements>
<incoming>sid-2668AC98-39E4-4B12-9052-930528086CAC</incoming>
<outgoing>sid-08D6385B-C6BB-45FC-A6BD-2369F392868D</outgoing>
<outgoing>sid-41205B5D-4DBA-4155-A0EE-7D71CE9AA459</outgoing>
</exclusiveGateway>
<task id="done" name="Done">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffcc" />
</extensionElements>
<incoming>sid-08D6385B-C6BB-45FC-A6BD-2369F392868D</incoming>
<outgoing>sid-F6160C0E-216C-4D72-98D1-CC5549327D55</outgoing>
</task>
<task id="go" name="Go">
<extensionElements>
<signavio:signavioMetaData metaKey="bgcolor" metaValue="#ffffcc" />
</extensionElements>
<incoming>sid-41205B5D-4DBA-4155-A0EE-7D71CE9AA459</incoming>
<incoming>sid-F3994F51-FE54-4910-A1F4-E5895AA1A612</incoming>
<outgoing>sid-3E0EBE59-75C8-465C-90CC-197CE808A96E</outgoing>
</task>
<sequenceFlow id="sid-7E15C71B-DE9E-4788-B140-A647C99FDC94" name="" sourceRef="first_split" targetRef="one" />
<sequenceFlow id="sid-B6E22A74-A691-453A-A789-B9F8AF787D7C" name="" sourceRef="first_split" targetRef="two" />
<sequenceFlow id="sid-0895E09C-077C-4D12-8C11-31F28CBC7740" name="" sourceRef="join_of_first" targetRef="retry" />
<sequenceFlow id="sid-CAEAD081-6E73-4C98-8656-C67DA18F5140" name="" sourceRef="two" targetRef="second_split" />
<sequenceFlow id="sid-918C653D-0960-4223-9C28-78114F238BCC" name="" sourceRef="second_split" targetRef="two_a" />
<sequenceFlow id="sid-FD82C2A6-7C54-4890-901E-A7E864F7605C" name="" sourceRef="second_split" targetRef="two_b" />
<sequenceFlow id="sid-961AF51C-9935-410E-AAA4-105B19186F5E" name="" sourceRef="two_a" targetRef="join_of_second_split" />
<sequenceFlow id="sid-47947925-21CD-46FF-8D3F-294B235AA4CF" name="" sourceRef="two_b" targetRef="join_of_second_split" />
<sequenceFlow id="sid-AFA38469-CD5C-42A2-9473-2EAEBA61F0C0" name="" sourceRef="join_of_second_split" targetRef="two_done" />
<sequenceFlow id="sid-231F8A51-752F-4CB3-8FD1-23D153238344" name="" sourceRef="two_done" targetRef="join_of_first" />
<sequenceFlow id="join_of_first_split" name="" sourceRef="one" targetRef="join_of_first" />
<sequenceFlow id="sid-2668AC98-39E4-4B12-9052-930528086CAC" name="" sourceRef="retry" targetRef="exclusive" />
<sequenceFlow id="sid-08D6385B-C6BB-45FC-A6BD-2369F392868D" name="No" sourceRef="exclusive" targetRef="done" />
<sequenceFlow id="sid-F6160C0E-216C-4D72-98D1-CC5549327D55" name="" sourceRef="done" targetRef="end" />
<sequenceFlow id="sid-41205B5D-4DBA-4155-A0EE-7D71CE9AA459" name="Yes" sourceRef="exclusive" targetRef="go" />
<sequenceFlow id="sid-3E0EBE59-75C8-465C-90CC-197CE808A96E" name="" sourceRef="go" targetRef="first_split" />
<sequenceFlow id="sid-F3994F51-FE54-4910-A1F4-E5895AA1A612" name="" sourceRef="start" targetRef="go" />
</process>
<bpmndi:BPMNDiagram id="sid-162a2324-4820-489a-9df8-04591b6b429a">
<bpmndi:BPMNPlane id="sid-4c9e28b7-9050-4a64-8a52-634f8f2febc3" bpmnElement="sid-5801c79c-823f-4040-b680-417ef5bcb3a2">
<bpmndi:BPMNShape id="sid-B2E5AD50-035A-4CE8-B8A3-B175A6767B00_gui" bpmnElement="sid-B2E5AD50-035A-4CE8-B8A3-B175A6767B00" isHorizontal="true">
<omgdc:Bounds x="120" y="90" width="794" height="619" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="sid-72009BCE-46B4-4B4B-AEAE-1E7199522142_gui" bpmnElement="sid-72009BCE-46B4-4B4B-AEAE-1E7199522142" isHorizontal="true">
<omgdc:Bounds x="150" y="90" width="764" height="619" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="sid-F3994F51-FE54-4910-A1F4-E5895AA1A612_gui" bpmnElement="sid-F3994F51-FE54-4910-A1F4-E5895AA1A612">
<omgdi:waypoint x="220" y="137" />
<omgdi:waypoint x="394" y="137" />
<omgdi:waypoint x="467" y="142" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="sid-3E0EBE59-75C8-465C-90CC-197CE808A96E_gui" bpmnElement="sid-3E0EBE59-75C8-465C-90CC-197CE808A96E">
<omgdi:waypoint x="467" y="167" />
<omgdi:waypoint x="414" y="191" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="sid-41205B5D-4DBA-4155-A0EE-7D71CE9AA459_gui" bpmnElement="sid-41205B5D-4DBA-4155-A0EE-7D71CE9AA459">
<omgdi:waypoint x="794" y="405" />
<omgdi:waypoint x="794.5" y="145" />
<omgdi:waypoint x="567" y="145" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="sid-F6160C0E-216C-4D72-98D1-CC5549327D55_gui" bpmnElement="sid-F6160C0E-216C-4D72-98D1-CC5549327D55">
<omgdi:waypoint x="794" y="577" />
<omgdi:waypoint x="794" y="630" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="sid-08D6385B-C6BB-45FC-A6BD-2369F392868D_gui" bpmnElement="sid-08D6385B-C6BB-45FC-A6BD-2369F392868D">
<omgdi:waypoint x="794" y="445" />
<omgdi:waypoint x="794" y="497" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="sid-2668AC98-39E4-4B12-9052-930528086CAC_gui" bpmnElement="sid-2668AC98-39E4-4B12-9052-930528086CAC">
<omgdi:waypoint x="715" y="425" />
<omgdi:waypoint x="774" y="425" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="sid-607CB05E-8762-41B6-AD43-C3970661A99D_gui" bpmnElement="join_of_first_split">
<omgdi:waypoint x="560" y="294" />
<omgdi:waypoint x="560" y="405" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="sid-231F8A51-752F-4CB3-8FD1-23D153238344_gui" bpmnElement="sid-231F8A51-752F-4CB3-8FD1-23D153238344">
<omgdi:waypoint x="475" y="535" />
<omgdi:waypoint x="491" y="425" />
<omgdi:waypoint x="540" y="425" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="sid-AFA38469-CD5C-42A2-9473-2EAEBA61F0C0_gui" bpmnElement="sid-AFA38469-CD5C-42A2-9473-2EAEBA61F0C0">
<omgdi:waypoint x="325" y="575" />
<omgdi:waypoint x="420" y="575" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="sid-47947925-21CD-46FF-8D3F-294B235AA4CF_gui" bpmnElement="sid-47947925-21CD-46FF-8D3F-294B235AA4CF">
<omgdi:waypoint x="344" y="448" />
<omgdi:waypoint x="305" y="448" />
<omgdi:waypoint x="305" y="555" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="sid-961AF51C-9935-410E-AAA4-105B19186F5E_gui" bpmnElement="sid-961AF51C-9935-410E-AAA4-105B19186F5E">
<omgdi:waypoint x="277" y="457" />
<omgdi:waypoint x="305" y="457" />
<omgdi:waypoint x="305" y="555" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="sid-FD82C2A6-7C54-4890-901E-A7E864F7605C_gui" bpmnElement="sid-FD82C2A6-7C54-4890-901E-A7E864F7605C">
<omgdi:waypoint x="301" y="358" />
<omgdi:waypoint x="394" y="358.5" />
<omgdi:waypoint x="394" y="408" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="sid-918C653D-0960-4223-9C28-78114F238BCC_gui" bpmnElement="sid-918C653D-0960-4223-9C28-78114F238BCC">
<omgdi:waypoint x="261" y="358" />
<omgdi:waypoint x="227" y="358.5" />
<omgdi:waypoint x="227" y="417" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="sid-CAEAD081-6E73-4C98-8656-C67DA18F5140_gui" bpmnElement="sid-CAEAD081-6E73-4C98-8656-C67DA18F5140">
<omgdi:waypoint x="281" y="294" />
<omgdi:waypoint x="281" y="338" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="sid-0895E09C-077C-4D12-8C11-31F28CBC7740_gui" bpmnElement="sid-0895E09C-077C-4D12-8C11-31F28CBC7740">
<omgdi:waypoint x="580" y="425" />
<omgdi:waypoint x="615" y="425" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="sid-B6E22A74-A691-453A-A789-B9F8AF787D7C_gui" bpmnElement="sid-B6E22A74-A691-453A-A789-B9F8AF787D7C">
<omgdi:waypoint x="394" y="220" />
<omgdi:waypoint x="394.5" y="254" />
<omgdi:waypoint x="331" y="254" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="sid-7E15C71B-DE9E-4788-B140-A647C99FDC94_gui" bpmnElement="sid-7E15C71B-DE9E-4788-B140-A647C99FDC94">
<omgdi:waypoint x="414" y="206" />
<omgdi:waypoint x="510" y="238" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="sid-B33EE043-AB93-4343-A1D4-7B267E2DAFBE_gui" bpmnElement="start">
<omgdc:Bounds x="190" y="122" width="30" height="30" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="sid-349F8C0C-45EA-489C-84DD-1D944F48D778_gui" bpmnElement="first_split">
<omgdc:Bounds x="374" y="180" width="40" height="40" />
<bpmndi:BPMNLabel>
<omgdc:Bounds x="371" y="220" width="46" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="sid-57463471-693A-42A2-9EC6-6460BEDECA86_gui" bpmnElement="one">
<omgdc:Bounds x="510" y="214" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="sid-CA089240-802A-4C32-9130-FB1A33DDCCC3_gui" bpmnElement="two">
<omgdc:Bounds x="231" y="214" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="sid-E976FBC2-266E-420F-8D4D-C8FBC6199090_gui" bpmnElement="join_of_first">
<omgdc:Bounds x="540" y="405" width="40" height="40" />
<bpmndi:BPMNLabel>
<omgdc:Bounds x="519" y="445" width="82" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="sid-F3A979E3-F586-4807-8223-1FAB5A5647B0_gui" bpmnElement="retry">
<omgdc:Bounds x="615" y="385" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="sid-51816945-79BF-47F9-BA3C-E95ABAE3D1DB_gui" bpmnElement="end">
<omgdc:Bounds x="780" y="630" width="28" height="28" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="sid-4F7F3AA6-4E8E-458D-BBEF-E03FC0646897_gui" bpmnElement="second_split">
<omgdc:Bounds x="261" y="338" width="40" height="40" />
<bpmndi:BPMNLabel>
<omgdc:Bounds x="250" y="378" width="62" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="sid-ABD788A3-CD57-4280-A22A-260B3AEEE138_gui" bpmnElement="two_a">
<omgdc:Bounds x="177" y="417" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="sid-E7B8898A-0D14-4E98-B3D7-736B94EE3FA7_gui" bpmnElement="two_b">
<omgdc:Bounds x="344" y="408" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="sid-A1609BD5-1E4A-47AE-8648-1DD41D1B1D58_gui" bpmnElement="join_of_second_split">
<omgdc:Bounds x="285" y="555" width="40" height="40" />
<bpmndi:BPMNLabel>
<omgdc:Bounds x="269" y="595" width="73" height="27" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="sid-1946C635-7886-4687-844F-C644FA6222B8_gui" bpmnElement="two_done">
<omgdc:Bounds x="420" y="535" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="sid-4C3B3C16-91DB-43E3-A816-FFEE572E61E1_gui" bpmnElement="exclusive" isMarkerVisible="true">
<omgdc:Bounds x="774" y="405" width="40" height="40" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="sid-55C018B8-C073-4292-9ED0-79BDE50E7498_gui" bpmnElement="done">
<omgdc:Bounds x="744" y="497" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="sid-E7904BFA-1F17-478E-91C9-C8A5B64190C9_gui" bpmnElement="go">
<omgdc:Bounds x="467" y="105" width="100" height="80" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>

View File

@ -1,104 +0,0 @@
<?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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_1svhxil" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.11.1" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.15.0">
<bpmn:process id="main" isExecutable="true">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_0j648np</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:exclusiveGateway id="Gateway_1hq5zma" default="Flow_13cp5nc">
<bpmn:incoming>Flow_0j648np</bpmn:incoming>
<bpmn:incoming>modify</bpmn:incoming>
<bpmn:outgoing>Flow_13cp5nc</bpmn:outgoing>
</bpmn:exclusiveGateway>
<bpmn:sequenceFlow id="Flow_0j648np" sourceRef="StartEvent_1" targetRef="Gateway_1hq5zma" />
<bpmn:task id="task_1" name="Task 1">
<bpmn:incoming>Flow_13cp5nc</bpmn:incoming>
<bpmn:outgoing>Flow_1r81vou</bpmn:outgoing>
</bpmn:task>
<bpmn:sequenceFlow id="Flow_13cp5nc" sourceRef="Gateway_1hq5zma" targetRef="task_1" />
<bpmn:task id="task_2" name="Task 2">
<bpmn:incoming>Flow_0m5s7t9</bpmn:incoming>
<bpmn:outgoing>Flow_0p7c88x</bpmn:outgoing>
</bpmn:task>
<bpmn:endEvent id="Event_07pdq0w">
<bpmn:incoming>Flow_1gm7381</bpmn:incoming>
<bpmn:incoming>Flow_0p7c88x</bpmn:incoming>
</bpmn:endEvent>
<bpmn:boundaryEvent id="timer" attachedToRef="task_1">
<bpmn:outgoing>Flow_0m5s7t9</bpmn:outgoing>
<bpmn:timerEventDefinition id="TimerEventDefinition_0hu2ovu">
<bpmn:timeDuration xsi:type="bpmn:tFormalExpression">"PT60S"</bpmn:timeDuration>
</bpmn:timerEventDefinition>
</bpmn:boundaryEvent>
<bpmn:sequenceFlow id="Flow_0m5s7t9" sourceRef="timer" targetRef="task_2" />
<bpmn:exclusiveGateway id="Gateway_123uzx5" default="Flow_1gm7381">
<bpmn:incoming>Flow_1r81vou</bpmn:incoming>
<bpmn:outgoing>modify</bpmn:outgoing>
<bpmn:outgoing>Flow_1gm7381</bpmn:outgoing>
</bpmn:exclusiveGateway>
<bpmn:sequenceFlow id="Flow_1r81vou" sourceRef="task_1" targetRef="Gateway_123uzx5" />
<bpmn:sequenceFlow id="modify" name="Modify&#10;" sourceRef="Gateway_123uzx5" targetRef="Gateway_1hq5zma">
<bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">modify</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<bpmn:sequenceFlow id="Flow_1gm7381" sourceRef="Gateway_123uzx5" targetRef="Event_07pdq0w" />
<bpmn:sequenceFlow id="Flow_0p7c88x" sourceRef="task_2" targetRef="Event_07pdq0w" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="main">
<bpmndi:BPMNEdge id="Flow_0j648np_di" bpmnElement="Flow_0j648np">
<di:waypoint x="215" y="197" />
<di:waypoint x="265" y="197" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_13cp5nc_di" bpmnElement="Flow_13cp5nc">
<di:waypoint x="315" y="197" />
<di:waypoint x="370" y="197" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0m5s7t9_di" bpmnElement="Flow_0m5s7t9">
<di:waypoint x="420" y="255" />
<di:waypoint x="420" y="300" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1r81vou_di" bpmnElement="Flow_1r81vou">
<di:waypoint x="470" y="197" />
<di:waypoint x="525" y="197" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1l30w6o_di" bpmnElement="modify">
<di:waypoint x="550" y="172" />
<di:waypoint x="550" y="100" />
<di:waypoint x="290" y="100" />
<di:waypoint x="290" y="172" />
<bpmndi:BPMNLabel>
<dc:Bounds x="404" y="82" width="33" height="27" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1gm7381_di" bpmnElement="Flow_1gm7381">
<di:waypoint x="575" y="197" />
<di:waypoint x="632" y="197" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0p7c88x_di" bpmnElement="Flow_0p7c88x">
<di:waypoint x="470" y="340" />
<di:waypoint x="650" y="340" />
<di:waypoint x="650" y="215" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="179" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_1hq5zma_di" bpmnElement="Gateway_1hq5zma" isMarkerVisible="true">
<dc:Bounds x="265" y="172" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1f3jg2c_di" bpmnElement="task_1">
<dc:Bounds x="370" y="157" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1r0ra56_di" bpmnElement="task_2">
<dc:Bounds x="370" y="300" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_123uzx5_di" bpmnElement="Gateway_123uzx5" isMarkerVisible="true">
<dc:Bounds x="525" y="172" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_07pdq0w_di" bpmnElement="Event_07pdq0w">
<dc:Bounds x="632" y="179" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1g1bbcs_di" bpmnElement="timer">
<dc:Bounds x="402" y="219" width="36" height="36" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -0,0 +1,600 @@
{
"serializer_version": "1.1",
"data": {},
"last_task": "65ef57f0-3fbf-4851-b7c8-a03de9a9062d",
"success": true,
"tasks": {
"fcccd5d5-8e9c-4dba-91c3-5b2ed44bb332": {
"id": "fcccd5d5-8e9c-4dba-91c3-5b2ed44bb332",
"parent": null,
"children": [
"e9523ea2-0474-4c36-a7c2-24ff56633ed7"
],
"last_state_change": 1678818080.7799659,
"state": 32,
"task_spec": "Root",
"triggered": false,
"workflow_name": "loops",
"internal_data": {},
"data": {}
},
"e9523ea2-0474-4c36-a7c2-24ff56633ed7": {
"id": "e9523ea2-0474-4c36-a7c2-24ff56633ed7",
"parent": "fcccd5d5-8e9c-4dba-91c3-5b2ed44bb332",
"children": [
"af4a1c32-12a7-46a7-b985-284fef1cb993"
],
"last_state_change": 1678818080.7888825,
"state": 32,
"task_spec": "Start",
"triggered": false,
"workflow_name": "loops",
"internal_data": {},
"data": {}
},
"af4a1c32-12a7-46a7-b985-284fef1cb993": {
"id": "af4a1c32-12a7-46a7-b985-284fef1cb993",
"parent": "e9523ea2-0474-4c36-a7c2-24ff56633ed7",
"children": [
"65ef57f0-3fbf-4851-b7c8-a03de9a9062d"
],
"last_state_change": 1678818080.7926495,
"state": 32,
"task_spec": "StartEvent_1",
"triggered": false,
"workflow_name": "loops",
"internal_data": {
"event_fired": true
},
"data": {}
},
"65ef57f0-3fbf-4851-b7c8-a03de9a9062d": {
"id": "65ef57f0-3fbf-4851-b7c8-a03de9a9062d",
"parent": "af4a1c32-12a7-46a7-b985-284fef1cb993",
"children": [
"b5200074-8196-40d3-8f83-204cf132856c"
],
"last_state_change": 1678818080.7970355,
"state": 32,
"task_spec": "initialize",
"triggered": false,
"workflow_name": "loops",
"internal_data": {},
"data": {
"counter": 0
}
},
"b5200074-8196-40d3-8f83-204cf132856c": {
"id": "b5200074-8196-40d3-8f83-204cf132856c",
"parent": "65ef57f0-3fbf-4851-b7c8-a03de9a9062d",
"children": [
"2ab8ec7f-a9ee-4891-a7a9-20250e2ab816"
],
"last_state_change": 1678818091.420421,
"state": 16,
"task_spec": "TIMER_EVENT",
"triggered": false,
"workflow_name": "loops",
"internal_data": {
"event_value": "2023-03-14T18:21:20.809141+00:00",
"event_fired": true
},
"data": {
"counter": 0
}
},
"2ab8ec7f-a9ee-4891-a7a9-20250e2ab816": {
"id": "2ab8ec7f-a9ee-4891-a7a9-20250e2ab816",
"parent": "b5200074-8196-40d3-8f83-204cf132856c",
"children": [
"259de884-e162-4e0b-8c86-d4827870e2ca"
],
"last_state_change": 1678818080.7815213,
"state": 4,
"task_spec": "increment_counter",
"triggered": false,
"workflow_name": "loops",
"internal_data": {},
"data": {}
},
"259de884-e162-4e0b-8c86-d4827870e2ca": {
"id": "259de884-e162-4e0b-8c86-d4827870e2ca",
"parent": "2ab8ec7f-a9ee-4891-a7a9-20250e2ab816",
"children": [
"bd7c4868-142b-487f-9ed3-6a384762dd55"
],
"last_state_change": 1678818080.7818034,
"state": 4,
"task_spec": "Activity_0w5u4k4",
"triggered": false,
"workflow_name": "loops",
"internal_data": {},
"data": {}
},
"bd7c4868-142b-487f-9ed3-6a384762dd55": {
"id": "bd7c4868-142b-487f-9ed3-6a384762dd55",
"parent": "259de884-e162-4e0b-8c86-d4827870e2ca",
"children": [
"2fc6691e-f99b-46f2-bebc-7ba729880d13",
"3a14ea66-76b3-4442-8cb3-71a89b9b92fd"
],
"last_state_change": 1678818080.782314,
"state": 4,
"task_spec": "Gateway_over_20",
"triggered": false,
"workflow_name": "loops",
"internal_data": {},
"data": {}
},
"2fc6691e-f99b-46f2-bebc-7ba729880d13": {
"id": "2fc6691e-f99b-46f2-bebc-7ba729880d13",
"parent": "bd7c4868-142b-487f-9ed3-6a384762dd55",
"children": [
"655b5f82-14dd-4edd-b88d-94e8cce02e78"
],
"last_state_change": 1678818080.783402,
"state": 1,
"task_spec": "end_event5",
"triggered": false,
"workflow_name": "loops",
"internal_data": {},
"data": {}
},
"655b5f82-14dd-4edd-b88d-94e8cce02e78": {
"id": "655b5f82-14dd-4edd-b88d-94e8cce02e78",
"parent": "2fc6691e-f99b-46f2-bebc-7ba729880d13",
"children": [],
"last_state_change": 1678818080.7840528,
"state": 1,
"task_spec": "loops.EndJoin",
"triggered": false,
"workflow_name": "loops",
"internal_data": {},
"data": {}
},
"3a14ea66-76b3-4442-8cb3-71a89b9b92fd": {
"id": "3a14ea66-76b3-4442-8cb3-71a89b9b92fd",
"parent": "bd7c4868-142b-487f-9ed3-6a384762dd55",
"children": [],
"last_state_change": 1678818080.7835343,
"state": 1,
"task_spec": "return_to_TIMER_EVENT",
"triggered": false,
"workflow_name": "loops",
"internal_data": {},
"data": {}
}
},
"root": "fcccd5d5-8e9c-4dba-91c3-5b2ed44bb332",
"spec": {
"name": "loops",
"description": "loops",
"file": "/home/essweine/work/sartography/code/SpiffWorkflow/tests/SpiffWorkflow/bpmn/data/too_many_loops.bpmn",
"task_specs": {
"Start": {
"id": "loops_1",
"name": "Start",
"description": "",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [],
"outputs": [
"StartEvent_1"
],
"typename": "StartTask"
},
"loops.EndJoin": {
"id": "loops_2",
"name": "loops.EndJoin",
"description": "",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"end_event5"
],
"outputs": [
"End"
],
"typename": "_EndJoin"
},
"End": {
"id": "loops_3",
"name": "End",
"description": "",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"loops.EndJoin"
],
"outputs": [],
"typename": "Simple"
},
"StartEvent_1": {
"id": "loops_4",
"name": "StartEvent_1",
"description": null,
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"Start"
],
"outputs": [
"initialize"
],
"lane": null,
"documentation": null,
"position": {
"x": 152.0,
"y": 159.0
},
"data_input_associations": [],
"data_output_associations": [],
"io_specification": null,
"event_definition": {
"internal": false,
"external": false,
"typename": "NoneEventDefinition"
},
"typename": "StartEvent",
"extensions": {}
},
"initialize": {
"id": "loops_5",
"name": "initialize",
"description": "initialize",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"StartEvent_1"
],
"outputs": [
"TIMER_EVENT"
],
"lane": null,
"documentation": null,
"position": {
"x": 250.0,
"y": 137.0
},
"data_input_associations": [],
"data_output_associations": [],
"io_specification": null,
"script": "counter = 0",
"typename": "ScriptTask",
"extensions": {}
},
"TIMER_EVENT": {
"id": "loops_6",
"name": "TIMER_EVENT",
"description": "Wait",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"Gateway_over_20",
"initialize"
],
"outputs": [
"increment_counter"
],
"lane": null,
"documentation": null,
"position": {
"x": 412.0,
"y": 159.0
},
"data_input_associations": [],
"data_output_associations": [],
"io_specification": null,
"event_definition": {
"internal": true,
"external": true,
"name": "Wait",
"expression": "\"PT.01S\"",
"typename": "DurationTimerEventDefinition"
},
"typename": "IntermediateCatchEvent",
"extensions": {}
},
"increment_counter": {
"id": "loops_7",
"name": "increment_counter",
"description": "increment counter",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"TIMER_EVENT"
],
"outputs": [
"Activity_0w5u4k4"
],
"lane": null,
"documentation": null,
"position": {
"x": 480.0,
"y": 137.0
},
"data_input_associations": [],
"data_output_associations": [],
"io_specification": null,
"script": "counter = counter + 1",
"typename": "ScriptTask",
"extensions": {}
},
"Activity_0w5u4k4": {
"id": "loops_8",
"name": "Activity_0w5u4k4",
"description": "call something",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"increment_counter"
],
"outputs": [
"Gateway_over_20"
],
"lane": null,
"documentation": null,
"position": {
"x": 620.0,
"y": 137.0
},
"data_input_associations": [],
"data_output_associations": [],
"io_specification": null,
"spec": "loops_ca",
"typename": "CallActivity",
"extensions": {}
},
"Gateway_over_20": {
"id": "loops_9",
"name": "Gateway_over_20",
"description": "is > 20",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"Activity_0w5u4k4"
],
"outputs": [
"end_event5",
"TIMER_EVENT"
],
"lane": null,
"documentation": null,
"position": {
"x": 755.0,
"y": 152.0
},
"data_input_associations": [],
"data_output_associations": [],
"io_specification": null,
"cond_task_specs": [
{
"condition": "counter >= 20",
"task_spec": "end_event5"
},
{
"condition": "counter < 20",
"task_spec": "TIMER_EVENT"
}
],
"choice": null,
"default_task_spec": null,
"typename": "ExclusiveGateway",
"extensions": {}
},
"end_event5": {
"id": "loops_10",
"name": "end_event5",
"description": null,
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"Gateway_over_20"
],
"outputs": [
"loops.EndJoin"
],
"lane": null,
"documentation": "### Results\nSubmission for Pre-Review was sent to the HSR-IRB on {{ sent_local_date_str }} at {{ sent_local_time_str }}.\n\nThe HSR-IRB started the Pre-Review process on {{ end_local_date_str }} at {{ end_local_time_str }} and assigned {{ irb_info.IRB_ADMINISTRATIVE_REVIEWER }} as the reviewer.\n\n### Metrics\n\n\nDays elapsed: {{days_delta }}",
"position": {
"x": 932.0,
"y": 159.0
},
"data_input_associations": [],
"data_output_associations": [],
"io_specification": null,
"event_definition": {
"internal": false,
"external": false,
"typename": "NoneEventDefinition"
},
"typename": "EndEvent",
"extensions": {}
},
"Root": {
"id": "loops_11",
"name": "Root",
"description": "",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [],
"outputs": [],
"typename": "Simple"
},
"return_to_TIMER_EVENT": {
"id": "loops_12",
"name": "return_to_TIMER_EVENT",
"description": "",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"Gateway_over_20",
"initialize"
],
"outputs": [],
"destination_id": "b5200074-8196-40d3-8f83-204cf132856c",
"destination_spec_name": "TIMER_EVENT",
"typename": "LoopResetTask"
}
},
"io_specification": null,
"data_objects": {},
"correlation_keys": {},
"typename": "BpmnProcessSpec"
},
"subprocess_specs": {
"loops_ca": {
"name": "loops_ca",
"description": "loops_ca",
"file": "/home/essweine/work/sartography/code/SpiffWorkflow/tests/SpiffWorkflow/bpmn/data/too_many_loops_call_activity.bpmn",
"task_specs": {
"Start": {
"id": "loops_ca_1",
"name": "Start",
"description": "",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [],
"outputs": [
"StartEvent_1"
],
"typename": "StartTask"
},
"loops_ca.EndJoin": {
"id": "loops_ca_2",
"name": "loops_ca.EndJoin",
"description": "",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"end_event5"
],
"outputs": [
"End"
],
"typename": "_EndJoin"
},
"End": {
"id": "loops_ca_3",
"name": "End",
"description": "",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"loops_ca.EndJoin"
],
"outputs": [],
"typename": "Simple"
},
"StartEvent_1": {
"id": "loops_ca_4",
"name": "StartEvent_1",
"description": null,
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"Start"
],
"outputs": [
"increment_counter"
],
"lane": null,
"documentation": null,
"position": {
"x": 152.0,
"y": 109.0
},
"data_input_associations": [],
"data_output_associations": [],
"io_specification": null,
"event_definition": {
"internal": false,
"external": false,
"typename": "NoneEventDefinition"
},
"typename": "StartEvent",
"extensions": {}
},
"increment_counter": {
"id": "loops_ca_5",
"name": "increment_counter",
"description": "increment counter",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"StartEvent_1"
],
"outputs": [
"end_event5"
],
"lane": null,
"documentation": null,
"position": {
"x": 220.0,
"y": 87.0
},
"data_input_associations": [],
"data_output_associations": [],
"io_specification": null,
"script": "counter2 = 1000",
"typename": "ScriptTask",
"extensions": {}
},
"end_event5": {
"id": "loops_ca_6",
"name": "end_event5",
"description": null,
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"increment_counter"
],
"outputs": [
"loops_ca.EndJoin"
],
"lane": null,
"documentation": "### Results\nSubmission for Pre-Review was sent to the HSR-IRB on {{ sent_local_date_str }} at {{ sent_local_time_str }}.\n\nThe HSR-IRB started the Pre-Review process on {{ end_local_date_str }} at {{ end_local_time_str }} and assigned {{ irb_info.IRB_ADMINISTRATIVE_REVIEWER }} as the reviewer.\n\n### Metrics\n\n\nDays elapsed: {{days_delta }}",
"position": {
"x": 362.0,
"y": 109.0
},
"data_input_associations": [],
"data_output_associations": [],
"io_specification": null,
"event_definition": {
"internal": false,
"external": false,
"typename": "NoneEventDefinition"
},
"typename": "EndEvent",
"extensions": {}
}
},
"io_specification": null,
"data_objects": {},
"correlation_keys": {},
"typename": "BpmnProcessSpec"
}
},
"subprocesses": {},
"bpmn_messages": [],
"correlations": {}
}

View File

@ -1,88 +0,0 @@
<?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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_0hx6iqe" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.11.1" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.15.0">
<bpmn:process id="main" name="Main" isExecutable="true">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_0nlj5lh</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:task id="initialize" name="Initialize">
<bpmn:incoming>Flow_0nlj5lh</bpmn:incoming>
<bpmn:incoming>Flow_16vai1a</bpmn:incoming>
<bpmn:outgoing>Flow_1lkecht</bpmn:outgoing>
</bpmn:task>
<bpmn:sequenceFlow id="Flow_1lkecht" sourceRef="initialize" targetRef="subprocess_in_loop" />
<bpmn:callActivity id="subprocess_in_loop" name="Subprocess in Loop" calledElement="subprocess">
<bpmn:incoming>Flow_1lkecht</bpmn:incoming>
<bpmn:outgoing>Flow_1vci114</bpmn:outgoing>
</bpmn:callActivity>
<bpmn:sequenceFlow id="Flow_1vci114" sourceRef="subprocess_in_loop" targetRef="call_2" />
<bpmn:exclusiveGateway id="Gateway_158gdvg" default="Flow_16vai1a">
<bpmn:incoming>Flow_0iui938</bpmn:incoming>
<bpmn:outgoing>Flow_0ew7zdi</bpmn:outgoing>
<bpmn:outgoing>Flow_16vai1a</bpmn:outgoing>
</bpmn:exclusiveGateway>
<bpmn:endEvent id="Event_0l6q7ei">
<bpmn:incoming>Flow_0ew7zdi</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_0ew7zdi" sourceRef="Gateway_158gdvg" targetRef="Event_0l6q7ei">
<bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">done</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<bpmn:sequenceFlow id="Flow_0iui938" sourceRef="call_2" targetRef="Gateway_158gdvg" />
<bpmn:callActivity id="call_2" name="Call Subprocess again" calledElement="subprocess">
<bpmn:incoming>Flow_1vci114</bpmn:incoming>
<bpmn:outgoing>Flow_0iui938</bpmn:outgoing>
</bpmn:callActivity>
<bpmn:sequenceFlow id="Flow_0nlj5lh" sourceRef="StartEvent_1" targetRef="initialize" />
<bpmn:sequenceFlow id="Flow_16vai1a" sourceRef="Gateway_158gdvg" targetRef="initialize" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="main">
<bpmndi:BPMNEdge id="Flow_1lkecht_di" bpmnElement="Flow_1lkecht">
<di:waypoint x="350" y="117" />
<di:waypoint x="420" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1vci114_di" bpmnElement="Flow_1vci114">
<di:waypoint x="520" y="117" />
<di:waypoint x="580" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0ew7zdi_di" bpmnElement="Flow_0ew7zdi">
<di:waypoint x="785" y="117" />
<di:waypoint x="862" y="117" />
<bpmndi:BPMNLabel>
<dc:Bounds x="1104" y="159" width="60" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0iui938_di" bpmnElement="Flow_0iui938">
<di:waypoint x="680" y="117" />
<di:waypoint x="735" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0nlj5lh_di" bpmnElement="Flow_0nlj5lh">
<di:waypoint x="188" y="117" />
<di:waypoint x="250" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_16vai1a_di" bpmnElement="Flow_16vai1a">
<di:waypoint x="760" y="142" />
<di:waypoint x="760" y="240" />
<di:waypoint x="300" y="240" />
<di:waypoint x="300" y="157" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Activity_0721i5u_di" bpmnElement="initialize">
<dc:Bounds x="250" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1lcptwy_di" bpmnElement="call_2">
<dc:Bounds x="580" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="152" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1stre5m_di" bpmnElement="subprocess_in_loop">
<dc:Bounds x="420" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_158gdvg_di" bpmnElement="Gateway_158gdvg" isMarkerVisible="true">
<dc:Bounds x="735" y="92" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0l6q7ei_di" bpmnElement="Event_0l6q7ei">
<dc:Bounds x="862" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -1,38 +0,0 @@
<?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:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_0vwjlip" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.11.1" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.15.0">
<bpmn:process id="subprocess" name="Subprocess" isExecutable="true">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_1dbtwxp</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_1dbtwxp" sourceRef="StartEvent_1" targetRef="Activity_1g5e8v7" />
<bpmn:endEvent id="Event_1ukgnws">
<bpmn:incoming>Flow_1t99mly</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_1t99mly" sourceRef="Activity_1g5e8v7" targetRef="Event_1ukgnws" />
<bpmn:task id="Activity_1g5e8v7" name="Subprocess Task">
<bpmn:incoming>Flow_1dbtwxp</bpmn:incoming>
<bpmn:outgoing>Flow_1t99mly</bpmn:outgoing>
</bpmn:task>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="subprocess">
<bpmndi:BPMNEdge id="Flow_1dbtwxp_di" bpmnElement="Flow_1dbtwxp">
<di:waypoint x="215" y="117" />
<di:waypoint x="270" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1t99mly_di" bpmnElement="Flow_1t99mly">
<di:waypoint x="370" y="117" />
<di:waypoint x="432" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1ukgnws_di" bpmnElement="Event_1ukgnws">
<dc:Bounds x="432" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0hql87y_di" bpmnElement="Activity_1g5e8v7">
<dc:Bounds x="270" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -1,125 +0,0 @@
<?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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_d4f3442" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.11.1">
<bpmn:process id="loops" isExecutable="true">
<bpmn:scriptTask id="increment_counter" name="increment counter">
<bpmn:incoming>Flow_1gb8wca</bpmn:incoming>
<bpmn:outgoing>Flow_1d2usdq</bpmn:outgoing>
<bpmn:script>counter = counter + 1</bpmn:script>
</bpmn:scriptTask>
<bpmn:sequenceFlow id="Flow_1d2usdq" sourceRef="increment_counter" targetRef="Activity_0w5u4k4" />
<bpmn:endEvent id="end_event5">
<bpmn:documentation>### Results
Submission for Pre-Review was sent to the HSR-IRB on {{ sent_local_date_str }} at {{ sent_local_time_str }}.
The HSR-IRB started the Pre-Review process on {{ end_local_date_str }} at {{ end_local_time_str }} and assigned {{ irb_info.IRB_ADMINISTRATIVE_REVIEWER }} as the reviewer.
### Metrics
Days elapsed: {{days_delta }}</bpmn:documentation>
<bpmn:incoming>Flow_1tj9oz1</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_1gb8wca" sourceRef="TIMER_EVENT" targetRef="increment_counter" />
<bpmn:intermediateCatchEvent id="TIMER_EVENT" name="Wait">
<bpmn:incoming>Flow_15jw6a4</bpmn:incoming>
<bpmn:incoming>Flow_0op1a19</bpmn:incoming>
<bpmn:outgoing>Flow_1gb8wca</bpmn:outgoing>
<bpmn:timerEventDefinition id="TimerEventDefinition_0x6divu">
<bpmn:timeDuration xsi:type="bpmn:tFormalExpression">"PT.01S"</bpmn:timeDuration>
</bpmn:timerEventDefinition>
</bpmn:intermediateCatchEvent>
<bpmn:exclusiveGateway id="Gateway_over_20" name="is &#62; 20">
<bpmn:incoming>Flow_0mxlkif</bpmn:incoming>
<bpmn:outgoing>Flow_1tj9oz1</bpmn:outgoing>
<bpmn:outgoing>Flow_0op1a19</bpmn:outgoing>
</bpmn:exclusiveGateway>
<bpmn:sequenceFlow id="Flow_1tj9oz1" name="Yes" sourceRef="Gateway_over_20" targetRef="end_event5">
<bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">counter &gt;= 20</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<bpmn:sequenceFlow id="Flow_0op1a19" name="No" sourceRef="Gateway_over_20" targetRef="TIMER_EVENT">
<bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">counter &lt; 20</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<bpmn:sequenceFlow id="Flow_15jw6a4" sourceRef="initialize" targetRef="TIMER_EVENT" />
<bpmn:scriptTask id="initialize" name="initialize">
<bpmn:incoming>Flow_0q7fkb7</bpmn:incoming>
<bpmn:outgoing>Flow_15jw6a4</bpmn:outgoing>
<bpmn:script>counter = 0</bpmn:script>
</bpmn:scriptTask>
<bpmn:sequenceFlow id="Flow_0mxlkif" sourceRef="Activity_0w5u4k4" targetRef="Gateway_over_20" />
<bpmn:callActivity id="Activity_0w5u4k4" name="call something" calledElement="loops_ca">
<bpmn:incoming>Flow_1d2usdq</bpmn:incoming>
<bpmn:outgoing>Flow_0mxlkif</bpmn:outgoing>
</bpmn:callActivity>
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_0q7fkb7</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_0q7fkb7" sourceRef="StartEvent_1" targetRef="initialize" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="loops">
<bpmndi:BPMNEdge id="Flow_0q7fkb7_di" bpmnElement="Flow_0q7fkb7">
<di:waypoint x="188" y="177" />
<di:waypoint x="250" y="177" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0mxlkif_di" bpmnElement="Flow_0mxlkif">
<di:waypoint x="720" y="177" />
<di:waypoint x="755" y="177" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_15jw6a4_di" bpmnElement="Flow_15jw6a4">
<di:waypoint x="350" y="177" />
<di:waypoint x="412" y="177" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0op1a19_di" bpmnElement="Flow_0op1a19">
<di:waypoint x="780" y="152" />
<di:waypoint x="780" y="80" />
<di:waypoint x="430" y="80" />
<di:waypoint x="430" y="159" />
<bpmndi:BPMNLabel>
<dc:Bounds x="598" y="62" width="15" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1tj9oz1_di" bpmnElement="Flow_1tj9oz1">
<di:waypoint x="805" y="177" />
<di:waypoint x="932" y="177" />
<bpmndi:BPMNLabel>
<dc:Bounds x="818" y="159" width="19" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1gb8wca_di" bpmnElement="Flow_1gb8wca">
<di:waypoint x="448" y="177" />
<di:waypoint x="480" y="177" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1d2usdq_di" bpmnElement="Flow_1d2usdq">
<di:waypoint x="580" y="177" />
<di:waypoint x="620" y="177" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Activity_1fgfg5d_di" bpmnElement="increment_counter">
<dc:Bounds x="480" y="137" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1tseamj_di" bpmnElement="end_event5">
<dc:Bounds x="932" y="159" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0whindt_di" bpmnElement="TIMER_EVENT">
<dc:Bounds x="412" y="159" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="419" y="202" width="22" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_0gr4bqq_di" bpmnElement="Gateway_over_20" isMarkerVisible="true">
<dc:Bounds x="755" y="152" width="50" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="768" y="209" width="33" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0whalo9_di" bpmnElement="initialize">
<dc:Bounds x="250" y="137" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0mmgsiw_di" bpmnElement="Activity_0w5u4k4">
<dc:Bounds x="620" y="137" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="152" y="159" width="36" height="36" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -1,48 +0,0 @@
<?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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_d4f3442" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.10.0">
<bpmn:process id="loops_ca" isExecutable="true">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_175n91v</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:scriptTask id="increment_counter" name="increment counter">
<bpmn:incoming>Flow_175n91v</bpmn:incoming>
<bpmn:outgoing>Flow_1d2usdq</bpmn:outgoing>
<bpmn:script>counter2 = 1000</bpmn:script>
</bpmn:scriptTask>
<bpmn:sequenceFlow id="Flow_1d2usdq" sourceRef="increment_counter" targetRef="end_event5" />
<bpmn:endEvent id="end_event5">
<bpmn:documentation>### Results
Submission for Pre-Review was sent to the HSR-IRB on {{ sent_local_date_str }} at {{ sent_local_time_str }}.
The HSR-IRB started the Pre-Review process on {{ end_local_date_str }} at {{ end_local_time_str }} and assigned {{ irb_info.IRB_ADMINISTRATIVE_REVIEWER }} as the reviewer.
### Metrics
Days elapsed: {{days_delta }}</bpmn:documentation>
<bpmn:incoming>Flow_1d2usdq</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_175n91v" sourceRef="StartEvent_1" targetRef="increment_counter" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="loops_ca">
<bpmndi:BPMNEdge id="Flow_175n91v_di" bpmnElement="Flow_175n91v">
<di:waypoint x="188" y="127" />
<di:waypoint x="220" y="127" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1d2usdq_di" bpmnElement="Flow_1d2usdq">
<di:waypoint x="320" y="127" />
<di:waypoint x="362" y="127" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="152" y="109" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1fgfg5d_di" bpmnElement="increment_counter">
<dc:Bounds x="220" y="87" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1tseamj_di" bpmnElement="end_event5">
<dc:Bounds x="362" y="109" width="36" height="36" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -1,157 +0,0 @@
<?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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_d4f3442" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.11.1">
<bpmn:process id="loops_sub" isExecutable="true">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_0q7fkb7</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_0q7fkb7" sourceRef="StartEvent_1" targetRef="initialize" />
<bpmn:scriptTask id="increment_counter" name="increment counter">
<bpmn:incoming>Flow_1gb8wca</bpmn:incoming>
<bpmn:outgoing>Flow_1d2usdq</bpmn:outgoing>
<bpmn:script>counter = counter + 1</bpmn:script>
</bpmn:scriptTask>
<bpmn:sequenceFlow id="Flow_1d2usdq" sourceRef="increment_counter" targetRef="Gateway_over_20" />
<bpmn:endEvent id="end_event5">
<bpmn:documentation>### Results
Submission for Pre-Review was sent to the HSR-IRB on {{ sent_local_date_str }} at {{ sent_local_time_str }}.
The HSR-IRB started the Pre-Review process on {{ end_local_date_str }} at {{ end_local_time_str }} and assigned {{ irb_info.IRB_ADMINISTRATIVE_REVIEWER }} as the reviewer.
### Metrics
Days elapsed: {{days_delta }}</bpmn:documentation>
<bpmn:incoming>Flow_1tj9oz1</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_1gb8wca" sourceRef="TIMER_EVENT" targetRef="increment_counter" />
<bpmn:intermediateCatchEvent id="TIMER_EVENT" name="Wait">
<bpmn:incoming>Flow_15jw6a4</bpmn:incoming>
<bpmn:incoming>Flow_1ivr6d7</bpmn:incoming>
<bpmn:outgoing>Flow_1gb8wca</bpmn:outgoing>
<bpmn:timerEventDefinition id="TimerEventDefinition_0x6divu">
<bpmn:timeDuration xsi:type="bpmn:tFormalExpression">"PT0.01S"</bpmn:timeDuration>
</bpmn:timerEventDefinition>
</bpmn:intermediateCatchEvent>
<bpmn:exclusiveGateway id="Gateway_over_20" name="is &#62; 20">
<bpmn:incoming>Flow_1d2usdq</bpmn:incoming>
<bpmn:outgoing>Flow_1tj9oz1</bpmn:outgoing>
<bpmn:outgoing>Flow_0op1a19</bpmn:outgoing>
</bpmn:exclusiveGateway>
<bpmn:sequenceFlow id="Flow_1tj9oz1" name="Yes" sourceRef="Gateway_over_20" targetRef="end_event5">
<bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">counter &gt;= 20</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<bpmn:sequenceFlow id="Flow_0op1a19" name="No" sourceRef="Gateway_over_20" targetRef="my_sub_process">
<bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">counter &lt; 20</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<bpmn:sequenceFlow id="Flow_15jw6a4" sourceRef="initialize" targetRef="TIMER_EVENT" />
<bpmn:scriptTask id="initialize" name="initialize">
<bpmn:incoming>Flow_0q7fkb7</bpmn:incoming>
<bpmn:outgoing>Flow_15jw6a4</bpmn:outgoing>
<bpmn:script>counter = 0
counter2 = 0
counter3 = 0</bpmn:script>
</bpmn:scriptTask>
<bpmn:sequenceFlow id="Flow_1ivr6d7" sourceRef="my_sub_process" targetRef="TIMER_EVENT" />
<bpmn:subProcess id="my_sub_process" name="Sub Process">
<bpmn:incoming>Flow_0op1a19</bpmn:incoming>
<bpmn:outgoing>Flow_1ivr6d7</bpmn:outgoing>
<bpmn:startEvent id="Event_0ubr6g5">
<bpmn:outgoing>Flow_1fcanuu</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_1fcanuu" sourceRef="Event_0ubr6g5" targetRef="Activity_05x1bpx" />
<bpmn:scriptTask id="Activity_05x1bpx" name="Increment Counter #2">
<bpmn:incoming>Flow_1fcanuu</bpmn:incoming>
<bpmn:outgoing>Flow_04le6u5</bpmn:outgoing>
<bpmn:script>counter2 += 1</bpmn:script>
</bpmn:scriptTask>
<bpmn:endEvent id="Event_0umaw1x">
<bpmn:incoming>Flow_04le6u5</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_04le6u5" sourceRef="Activity_05x1bpx" targetRef="Event_0umaw1x" />
</bpmn:subProcess>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="loops_sub">
<bpmndi:BPMNEdge id="Flow_1ivr6d7_di" bpmnElement="Flow_1ivr6d7">
<di:waypoint x="490" y="310" />
<di:waypoint x="430" y="310" />
<di:waypoint x="430" y="145" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_15jw6a4_di" bpmnElement="Flow_15jw6a4">
<di:waypoint x="350" y="127" />
<di:waypoint x="412" y="127" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0op1a19_di" bpmnElement="Flow_0op1a19">
<di:waypoint x="920" y="152" />
<di:waypoint x="920" y="310" />
<di:waypoint x="840" y="310" />
<bpmndi:BPMNLabel>
<dc:Bounds x="863" y="292" width="15" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1tj9oz1_di" bpmnElement="Flow_1tj9oz1">
<di:waypoint x="945" y="127" />
<di:waypoint x="1072" y="127" />
<bpmndi:BPMNLabel>
<dc:Bounds x="958" y="109" width="19" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1gb8wca_di" bpmnElement="Flow_1gb8wca">
<di:waypoint x="448" y="127" />
<di:waypoint x="625" y="127" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1d2usdq_di" bpmnElement="Flow_1d2usdq">
<di:waypoint x="725" y="127" />
<di:waypoint x="895" y="127" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0q7fkb7_di" bpmnElement="Flow_0q7fkb7">
<di:waypoint x="188" y="127" />
<di:waypoint x="250" y="127" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="152" y="109" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1fgfg5d_di" bpmnElement="increment_counter">
<dc:Bounds x="625" y="87" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1tseamj_di" bpmnElement="end_event5">
<dc:Bounds x="1072" y="109" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0whindt_di" bpmnElement="TIMER_EVENT">
<dc:Bounds x="412" y="109" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="419" y="85" width="22" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_0gr4bqq_di" bpmnElement="Gateway_over_20" isMarkerVisible="true">
<dc:Bounds x="895" y="102" width="50" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="908" y="159" width="33" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0whalo9_di" bpmnElement="initialize">
<dc:Bounds x="250" y="87" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0v3bik3_di" bpmnElement="my_sub_process" isExpanded="true">
<dc:Bounds x="490" y="210" width="350" height="200" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_04le6u5_di" bpmnElement="Flow_04le6u5">
<di:waypoint x="720" y="310" />
<di:waypoint x="782" y="310" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1fcanuu_di" bpmnElement="Flow_1fcanuu">
<di:waypoint x="566" y="310" />
<di:waypoint x="620" y="310" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Event_0ubr6g5_di" bpmnElement="Event_0ubr6g5">
<dc:Bounds x="530" y="292" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_08o251p_di" bpmnElement="Activity_05x1bpx">
<dc:Bounds x="620" y="270" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0umaw1x_di" bpmnElement="Event_0umaw1x">
<dc:Bounds x="782" y="292" width="36" height="36" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -51,7 +51,7 @@ class CallActivityEscalationTest(BpmnWorkflowTestCase):
task.set_data(should_escalate=True)
self.workflow.do_engine_steps()
self.save_restore()
self.workflow.complete_all()
self.workflow.run_all()
self.assertEqual(True, self.workflow.is_completed())
self.assertEqual(True, 'EndEvent_specific1_noninterrupting_normal' in completed_set)
@ -81,7 +81,7 @@ class CallActivityEscalationTest(BpmnWorkflowTestCase):
task.set_data(should_escalate=False)
self.workflow.do_engine_steps()
self.save_restore()
self.workflow.complete_all()
self.workflow.run_all()
self.assertEqual(True, self.workflow.is_completed())
self.assertEqual(True, 'EndEvent_specific1_noninterrupting_normal' in completed_set)
@ -109,7 +109,7 @@ class CallActivityEscalationTest(BpmnWorkflowTestCase):
track_workflow(self.spec, completed_set)
self.workflow.do_engine_steps()
self.save_restore()
self.workflow.complete_all()
self.workflow.run_all()
self.assertEqual(True, self.workflow.is_completed())
self.assertEqual(True, 'EndEvent_specific1_noninterrupting_normal' in completed_set)

View File

@ -28,7 +28,7 @@ class EventBasedGatewayTest(BpmnWorkflowTestCase):
if save_restore:
self.save_restore()
self.workflow.script_engine = self.script_engine
self.assertEqual(len(waiting_tasks), 1)
self.assertEqual(len(waiting_tasks), 2)
self.workflow.catch(MessageEventDefinition('message_1'))
self.workflow.do_engine_steps()
self.workflow.refresh_waiting_tasks()
@ -41,7 +41,7 @@ class EventBasedGatewayTest(BpmnWorkflowTestCase):
self.workflow.do_engine_steps()
waiting_tasks = self.workflow.get_waiting_tasks()
self.assertEqual(len(waiting_tasks), 1)
self.assertEqual(len(waiting_tasks), 2)
timer_event = waiting_tasks[0].task_spec.event_definition.event_definitions[-1]
self.workflow.catch(timer_event)
self.workflow.refresh_waiting_tasks()

View File

@ -33,7 +33,7 @@ class MultipleEventsTest(BpmnWorkflowTestCase):
task = self.workflow.get_tasks(TaskState.READY)[0]
# Move to User Task 1
self.workflow.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
task = self.workflow.get_tasks(TaskState.READY)[0]
self.assertEqual('UserTaskOne', task.get_name())
@ -52,10 +52,10 @@ class MultipleEventsTest(BpmnWorkflowTestCase):
task = self.workflow.get_tasks(TaskState.READY)[0]
# Move to User Task 2
self.workflow.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
task = self.workflow.get_tasks(TaskState.READY)[0]
self.workflow.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
task = self.workflow.get_tasks(TaskState.READY)[0]
self.assertEqual('UserTaskTwo', task.get_name())

View File

@ -42,6 +42,6 @@ class MultipleThrowEventStartsEventTest(BpmnWorkflowTestCase):
self.workflow.do_engine_steps()
ready_tasks = self.workflow.get_ready_user_tasks()
self.assertEqual(len(ready_tasks), 1)
ready_tasks[0].complete()
ready_tasks[0].run()
self.workflow.do_engine_steps()
self.assertEqual(self.workflow.is_completed(), True)

View File

@ -62,7 +62,7 @@ class NITimerDurationTest(BpmnWorkflowTestCase):
task.data['delay_reason'] = 'Just Because'
elif task.task_spec.name == 'Activity_Work':
task.data['work_done'] = 'Yes'
task.complete()
task.run()
self.workflow.refresh_waiting_tasks()
self.workflow.do_engine_steps()
self.assertEqual(self.workflow.is_completed(),True)

View File

@ -55,11 +55,11 @@ class TimerCycleTest(BpmnWorkflowTestCase):
time.sleep(0.05)
self.workflow.refresh_waiting_tasks()
events = self.workflow.waiting_events()
if loopcount == 0:
# Wait time is 0.1s, so the first time through, there should still be a waiting event
if loopcount < 2:
# Wait time is 0.1s, two child tasks are created
self.assertEqual(len(events), 1)
else:
# By the second iteration, both should be complete
# By the third iteration, the event should no longer be waiting
self.assertEqual(len(events), 0)
# Get coffee still ready

View File

@ -39,7 +39,7 @@ class TimerDurationTest(BpmnWorkflowTestCase):
# Make sure the task can still be called.
task = self.workflow.get_ready_user_tasks()[0]
task.complete()
task.run()
self.workflow.do_engine_steps()
self.assertTrue(self.workflow.is_completed())

View File

@ -24,7 +24,7 @@ class TimerDurationTest(BpmnWorkflowTestCase):
def actual_test(self,save_restore = False):
self.workflow.do_engine_steps()
ready_tasks = self.workflow.get_tasks(TaskState.READY)
ready_tasks[0].complete()
ready_tasks[0].run()
self.workflow.do_engine_steps()
loopcount = 0
@ -43,7 +43,7 @@ class TimerDurationTest(BpmnWorkflowTestCase):
self.assertEqual(subworkflow.state, TaskState.CANCELLED)
ready_tasks = self.workflow.get_ready_user_tasks()
while len(ready_tasks) > 0:
ready_tasks[0].complete()
ready_tasks[0].run()
ready_tasks = self.workflow.get_ready_user_tasks()
self.workflow.do_engine_steps()
self.assertTrue(self.workflow.is_completed())

View File

@ -19,11 +19,11 @@ class TransactionSubprocessTest(BpmnWorkflowTestCase):
ready_tasks = self.workflow.get_tasks(TaskState.READY)
ready_tasks[0].update_data({'value': 'asdf'})
ready_tasks[0].complete()
ready_tasks[0].run()
self.workflow.do_engine_steps()
ready_tasks = self.workflow.get_tasks(TaskState.READY)
ready_tasks[0].update_data({'quantity': 2})
ready_tasks[0].complete()
ready_tasks[0].run()
self.workflow.do_engine_steps()
self.assertIn('value', self.workflow.last_task.data)
@ -48,7 +48,7 @@ class TransactionSubprocessTest(BpmnWorkflowTestCase):
# If value == '', we cancel
ready_tasks[0].update_data({'value': ''})
ready_tasks[0].complete()
ready_tasks[0].run()
self.workflow.do_engine_steps()
# If the subprocess gets cancelled, verify that data set there does not persist
@ -72,13 +72,13 @@ class TransactionSubprocessTest(BpmnWorkflowTestCase):
ready_tasks = self.workflow.get_tasks(TaskState.READY)
ready_tasks[0].update_data({'value': 'asdf'})
ready_tasks[0].complete()
ready_tasks[0].run()
self.workflow.do_engine_steps()
ready_tasks = self.workflow.get_tasks(TaskState.READY)
# If quantity == 0, we throw an error with no error code
ready_tasks[0].update_data({'quantity': 0})
ready_tasks[0].complete()
ready_tasks[0].run()
self.workflow.do_engine_steps()
# We formerly checked that subprocess data does not persist, but I think it should persist
@ -103,13 +103,13 @@ class TransactionSubprocessTest(BpmnWorkflowTestCase):
ready_tasks = self.workflow.get_tasks(TaskState.READY)
ready_tasks[0].update_data({'value': 'asdf'})
ready_tasks[0].complete()
ready_tasks[0].run()
self.workflow.do_engine_steps()
ready_tasks = self.workflow.get_tasks(TaskState.READY)
# If quantity < 0, we throw 'Error 1'
ready_tasks[0].update_data({'quantity': -1})
ready_tasks[0].complete()
ready_tasks[0].run()
self.workflow.do_engine_steps()
# The cancel boundary event should be cancelled

View File

@ -142,7 +142,7 @@ class BpmnWorkflowSerializerTest(BaseTestCase):
def test_serialize_workflow_where_script_task_includes_function(self):
self.workflow.do_engine_steps()
ready_tasks = self.workflow.get_ready_user_tasks()
ready_tasks[0].complete()
ready_tasks[0].run()
self.workflow.do_engine_steps()
results = self.serializer.serialize_json(self.workflow)
assert self.workflow.is_completed()
@ -161,7 +161,7 @@ class BpmnWorkflowSerializerTest(BaseTestCase):
self.assertEqual(w1.data, w2.data)
self.assertEqual(w1.name, w2.name)
for task in w1.get_ready_user_tasks():
w2_task = w2.get_task(task.id)
w2_task = w2.get_task_from_id(task.id)
self.assertIsNotNone(w2_task)
self.assertEqual(task.data, w2_task.data)

View File

@ -16,11 +16,12 @@ class Version_1_0_Test(BaseTestCase):
def test_convert_subprocess(self):
# The serialization used here comes from NestedSubprocessTest saved at line 25 with version 1.0
fn = os.path.join(self.DATA_DIR, 'serialization', 'v1.0.json')
wf = self.serializer.deserialize_json(open(fn).read())
with open(fn) as fh:
wf = self.serializer.deserialize_json(fh.read())
# We should be able to finish the workflow from this point
ready_tasks = wf.get_tasks(TaskState.READY)
self.assertEqual('Action3', ready_tasks[0].task_spec.description)
ready_tasks[0].complete()
ready_tasks[0].run()
wf.do_engine_steps()
self.assertEqual(True, wf.is_completed())
@ -49,7 +50,7 @@ class Version_1_1_Test(BaseTestCase):
self.assertEqual(len(task.task_spec.cond_task_specs), 2)
ready_task = wf.get_ready_user_tasks()[0]
ready_task.data['NeedClarification'] = 'Yes'
ready_task.complete()
ready_task.run()
wf.do_engine_steps()
ready_task = wf.get_ready_user_tasks()[0]
self.assertEqual(ready_task.task_spec.name, 'Activity_A2')
@ -59,3 +60,14 @@ class Version_1_1_Test(BaseTestCase):
with self.assertRaises(VersionMigrationError) as ctx:
wf = self.serializer.deserialize_json(open(fn).read())
self.assertEqual(ctx.exception.message, "This workflow cannot be migrated because it contains MultiInstance Tasks")
def test_remove_loop_reset(self):
fn = os.path.join(self.DATA_DIR, 'serialization', 'v1.1-loop-reset.json')
wf = self.serializer.deserialize_json(open(fn).read())
# Allow 3 seconds max to allow this test to complete (there are 20 loops with a 0.1s timer)
end = time.time() + 3
while not wf.is_completed() and time.time() < end:
wf.do_engine_steps()
wf.refresh_waiting_tasks()
self.assertTrue(wf.is_completed())
self.assertEqual(wf.last_task.data['counter'], 20)

View File

@ -39,7 +39,7 @@ class CallActivityMessageTest(BaseTestCase):
current_task = ready_tasks[0]
self.assertEqual(current_task.task_spec.name,step[0])
current_task.update_data(step[1])
current_task.complete()
current_task.run()
self.workflow.do_engine_steps()
self.workflow.refresh_waiting_tasks()
if save_restore: self.save_restore()

View File

@ -52,7 +52,7 @@ class ClashingNameTest(BaseTestCase):
firsttaskid = task.id
self.assertEqual(step['taskname'], task.task_spec.name)
task.update_data({step['formvar']: step['answer']})
self.workflow.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
if save_restore: self.save_restore()
@ -68,7 +68,7 @@ class ClashingNameTest(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.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
if save_restore: self.save_restore()

View File

@ -29,7 +29,7 @@ class DMNCustomScriptTest(BaseTestCase):
def complete_manual_task(self):
manual_task = self.workflow.get_tasks_from_spec_name('manual_task')[0]
self.workflow.complete_task_from_id(manual_task.id)
self.workflow.run_task_from_id(manual_task.id)
self.workflow.do_engine_steps()
def testDmnHappy(self):

View File

@ -16,7 +16,7 @@ class DMNDictTest(BaseTestCase):
self.workflow = BpmnWorkflow(self.spec)
self.workflow.do_engine_steps()
x = self.workflow.get_ready_user_tasks()
self.workflow.complete_task_from_id(x[0].id)
self.workflow.run_task_from_id(x[0].id)
self.workflow.do_engine_steps()
self.assertDictEqual(self.workflow.last_task.data, self.expectedResult)
@ -25,7 +25,7 @@ class DMNDictTest(BaseTestCase):
self.workflow.do_engine_steps()
self.save_restore()
x = self.workflow.get_ready_user_tasks()
self.workflow.complete_task_from_id(x[0].id)
self.workflow.run_task_from_id(x[0].id)
self.workflow.do_engine_steps()
self.save_restore()
self.assertDictEqual(self.workflow.last_task.data, self.expectedResult)

View File

@ -41,7 +41,7 @@ class ExternalMessageBoundaryTest(BaseTestCase):
self.assertEqual(True, ready_tasks[1].data['caughtinterrupt'])
self.assertEqual('Meaningless User Task',ready_tasks[0].task_spec.description)
self.assertEqual(False, ready_tasks[0].data['caughtinterrupt'])
ready_tasks[1].complete()
ready_tasks[1].run()
self.workflow.do_engine_steps()
# what I think is going on here is that when we hit the reset, it is updating the
# last_task and appending the data to whatever happened there, so it would make sense that
@ -52,7 +52,7 @@ class ExternalMessageBoundaryTest(BaseTestCase):
# 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')
event = self.workflow.get_tasks_from_spec_name('Event_19detfv')[0]
event.complete()
event.run()
self.assertEqual('SomethingDrastic', event.data['reset_var'])
self.assertEqual(False, event.data['caughtinterrupt'])

View File

@ -31,7 +31,7 @@ class BusinessRuleTaskParserTest(BaseTestCase):
self.assertTrue(True, "An error was raised..")
self.assertEqual("InvalidDecisionTaskId", we.task_spec.name)
self.maxDiff = 1000
self.assertEquals("Error evaluating expression 'spam= 1'. Rule failed on row 1. Business Rule Task 'Invalid Decision'.", str(we))
self.assertEqual("Error evaluating expression 'spam= 1'. Rule failed on row 1. Business Rule Task 'Invalid Decision'.", str(we))
def suite():
return unittest.TestLoader().loadTestsFromTestCase(BusinessRuleTaskParserTest)

View File

@ -41,7 +41,7 @@ class MessageBoundaryTest(BaseTestCase):
if task.task_spec.name == step[0]:
task.update_data(step[1])
self.workflow.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
time.sleep(.01)
self.workflow.refresh_waiting_tasks()

View File

@ -23,10 +23,10 @@ class MultiInstanceDMNTest(BaseTestCase):
self.save_restore()
self.workflow.do_engine_steps()
self.workflow.complete_next()
self.workflow.run_next()
self.save_restore()
self.workflow.do_engine_steps()
self.workflow.complete_next()
self.workflow.run_next()
self.save_restore()
self.workflow.do_engine_steps()
self.save_restore()

View File

@ -29,7 +29,7 @@ class NIMessageBoundaryTest(BaseTestCase):
ready_tasks = self.workflow.get_tasks(TaskState.READY)
self.assertEqual(1, len(ready_tasks))
self.workflow.complete_task_from_id(ready_tasks[0].id)
self.workflow.run_task_from_id(ready_tasks[0].id)
self.workflow.do_engine_steps()
# first we run through a couple of steps where we answer No to each
@ -45,7 +45,7 @@ class NIMessageBoundaryTest(BaseTestCase):
'We got a ready task that we did not expect - %s'%(
task.task_spec.name))
task.data[response[0]] = response[1]
self.workflow.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
# if we have a list of tasks - that list becomes invalid
# after we do a save restore, so I'm completing the list
@ -66,7 +66,7 @@ class NIMessageBoundaryTest(BaseTestCase):
'We got a ready task that we did not expect - %s'%(
task.task_spec.name))
task.data[response[0]] = response[1]
self.workflow.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
if save_restore: self.save_restore()
@ -75,14 +75,14 @@ class NIMessageBoundaryTest(BaseTestCase):
task = ready_tasks[0]
self.assertEqual(task.task_spec.name,'Activity_DoWork')
task.data['work_done'] = 'Yes'
self.workflow.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
ready_tasks = self.workflow.get_tasks(TaskState.READY)
self.assertEqual(len(ready_tasks), 1)
task = ready_tasks[0]
self.assertEqual(task.task_spec.name, 'Activity_WorkCompleted')
task.data['work_completed'] = 'Lots of Stuff'
self.workflow.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
self.assertEqual(self.workflow.is_completed(),True)
self.assertEqual(self.workflow.last_task.data,{'Event_InterruptBoundary_Response': 'Youre late!',

View File

@ -32,7 +32,7 @@ class ParseMultiInstanceTest(BaseTestCase):
self.assertEqual(len(ready_tasks), 3)
for task in ready_tasks:
task.data['output_item'] = task.data['output_item'] * 2
task.complete()
task.run()
self.workflow.do_engine_steps()
self.assertTrue(self.workflow.is_completed())
@ -58,7 +58,7 @@ class ParseMultiInstanceTest(BaseTestCase):
self.assertEqual(len(ready_tasks), 3)
for task in ready_tasks:
task.data['output_item'] = task.data['output_item'] * 2
task.complete()
task.run()
self.workflow.do_engine_steps()
self.assertTrue(self.workflow.is_completed())
@ -84,7 +84,7 @@ class ParseMultiInstanceTest(BaseTestCase):
self.assertEqual(len(ready_tasks), 3)
for task in ready_tasks:
task.data['input_item'] = task.data['input_item'] * 2
task.complete()
task.run()
self.workflow.do_engine_steps()
self.assertTrue(self.workflow.is_completed())

View File

@ -73,7 +73,7 @@ class ResetTokenTestNestedParallel(BaseTestCase):
firsttaskid = task.id
self.assertEqual(step['taskname'], task.task_spec.name)
task.update_data({step['formvar']: step['answer']})
self.workflow.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
if save_restore: self.save_restore()
self.workflow.reset_task_from_id(firsttaskid)
@ -91,7 +91,7 @@ class ResetTokenTestNestedParallel(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.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
if save_restore: self.save_restore()
notworking = self.workflow.get_ready_user_tasks()
@ -148,7 +148,7 @@ class ResetTokenTestNestedParallel(BaseTestCase):
firsttaskid = task.id
self.assertEqual(step['taskname'], task.task_spec.name)
task.update_data({step['formvar']: step['answer']})
self.workflow.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
if save_restore: self.save_restore()
@ -182,7 +182,7 @@ class ResetTokenTestNestedParallel(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.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
if save_restore: self.save_restore()

View File

@ -76,7 +76,7 @@ class ResetTokenTestParallelMatrix(BaseTestCase):
firsttaskid = task.id
self.assertEqual(step['taskname'], task.task_spec.name)
task.update_data({step['formvar']: step['answer']})
self.workflow.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
if save_restore: self.save_restore()
@ -96,7 +96,7 @@ class ResetTokenTestParallelMatrix(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.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
if save_restore: self.save_restore()
@ -154,7 +154,7 @@ class ResetTokenTestParallelMatrix(BaseTestCase):
firsttaskid = task.id
self.assertEqual(step['taskname'], task.task_spec.name)
task.update_data({step['formvar']: step['answer']})
self.workflow.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
if save_restore: self.save_restore()
@ -190,7 +190,7 @@ class ResetTokenTestParallelMatrix(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.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
if save_restore: self.save_restore()

View File

@ -29,22 +29,19 @@ class ResetTokenParallelTaskCountTest(BaseTestCase):
# number of tasks
self.workflow.do_engine_steps()
self.assertEquals(total, len(self.workflow.get_tasks()))
self.assertEqual(total, len(self.workflow.get_tasks()))
# Tell the exclusive gateway to skip the parallel tasks section.
# We should still have the same number of tasks.
data = {'skipParallel': True}
task = self.workflow.get_ready_user_tasks()[0]
task.data = data
self.workflow.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.assertEquals(total, len(self.workflow.get_tasks()))
# Reset the token to the first user task.
# We should still have the same number of tasks.
self.workflow.task_tree.dump()
task.reset_token({}, reset_data=True)
print('=-----')
self.workflow.task_tree.dump()
self.assertEquals(total, len(self.workflow.get_tasks()))
self.assertEquals(1, len(self.workflow.get_ready_user_tasks()))

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.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
if save_restore:
self.save_restore()
@ -75,7 +75,7 @@ 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.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
if save_restore:
self.save_restore()
@ -128,7 +128,7 @@ class ResetTokenTestSubProcess(BaseTestCase):
firsttaskid = task.id
self.assertEqual(step['taskname'], task.task_spec.name)
task.update_data({step['formvar']: step['answer']})
self.workflow.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
if save_restore: self.save_restore()
@ -164,7 +164,7 @@ 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.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
if save_restore: self.save_restore()

View File

@ -54,7 +54,7 @@ class ResetTokenTest(BaseTestCase):
firsttaskid = task.id
self.assertEqual(step['taskname'], task.task_spec.name)
task.update_data({step['formvar']: step['answer']})
self.workflow.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
if save_restore: self.save_restore()
@ -70,7 +70,7 @@ class ResetTokenTest(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.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
if save_restore: self.save_restore()

View File

@ -48,7 +48,7 @@ class StartMessageTest(BaseTestCase):
current_task = ready_tasks[0]
self.assertEqual(current_task.task_spec.name,step[0])
current_task.update_data(step[1])
current_task.complete()
current_task.run()
self.workflow.do_engine_steps()
self.workflow.refresh_waiting_tasks()
if save_restore:

View File

@ -31,7 +31,7 @@ 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.complete_task_from_id(task.id)
self.workflow.run_task_from_id(task.id)
self.workflow.do_engine_steps()
if save_restore: self.save_restore()

View File

@ -16,22 +16,22 @@ class UserTaskParserTest(BaseTestCase):
def testGetEnumField(self):
form = self.spec.task_specs['Task_User_Select_Type'].form
self.assertEquals("Fact", form.key)
self.assertEquals(1, len(form.fields))
self.assertEquals("type", form.fields[0].id)
self.assertEquals(3, len(form.fields[0].options))
self.assertEqual("Fact", form.key)
self.assertEqual(1, len(form.fields))
self.assertEqual("type", form.fields[0].id)
self.assertEqual(3, len(form.fields[0].options))
def testGetFieldProperties(self):
form = self.spec.task_specs['Task_User_Select_Type'].form
self.assertEquals(1, len(form.fields[0].properties))
self.assertEquals('description', form.fields[0].properties[0].id)
self.assertEquals('Choose from the list of available types of random facts', form.fields[0].properties[0].value)
self.assertEqual(1, len(form.fields[0].properties))
self.assertEqual('description', form.fields[0].properties[0].id)
self.assertEqual('Choose from the list of available types of random facts', form.fields[0].properties[0].value)
def testGetFieldValidation(self):
form = self.spec.task_specs['Task_User_Select_Type'].form
self.assertEquals(1, len(form.fields[0].validation))
self.assertEquals('maxlength', form.fields[0].validation[0].name)
self.assertEquals('25', form.fields[0].validation[0].config)
self.assertEqual(1, len(form.fields[0].validation))
self.assertEqual('maxlength', form.fields[0].validation[0].name)
self.assertEqual('25', form.fields[0].validation[0].config)
def testNoFormDoesNotBombOut(self):
self.load_workflow_spec('no_form.bpmn', 'no_form')

View File

@ -20,12 +20,11 @@ class UserTaskSpecTest(unittest.TestCase):
self.user_spec = self.create_instance()
def testConstructor(self):
self.assertEquals(self.user_spec.name, 'userTask')
self.assertEqual(self.user_spec.name, 'userTask')
self.assertEqual(self.user_spec.data, {})
self.assertEqual(self.user_spec.defines, {})
self.assertEqual(self.user_spec.pre_assign, [])
self.assertEqual(self.user_spec.post_assign, [])
self.assertEqual(self.user_spec.locks, [])
def test_set_form(self):
self.assertEqual(self.form, self.user_spec.form)

View File

@ -0,0 +1,185 @@
# -*- coding: utf-8 -*-
from unittest import TestCase
from .pattern_base import WorkflowPatternTestCase
# This combines the old pattern tests with the old serializer tests, creating one test per pattern
# that tests the tasks in it can be serialized with our serializers and the workflows run with the
# expected output. This format is a little annoying (inheriting from two classes with the actual
# work being done in the secondary class); however, this is the most concise thing I could manage.
#
# There were also a fair amount of never-used options in those tests, so the tests in the base case
# are a lot simpler than the ones they replaced.
class SequenceTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/sequence')
class ParallelSplitTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/parallel_split')
class SynchronizationTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/synchronization')
class ExclusiveChoiceTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/exclusive_choice')
class SimpleMergeTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/simple_merge')
class MultiChoiceTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/multi_choice')
class StructuredSynchronizingMergeTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/structured_synchronizing_merge')
class MultiMergeTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/multi_merge')
class StructuredDiscriminatorTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/structured_discriminator')
class BlockingDiscriminatorTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/blocking_discriminator')
class CacncellingDiscriminatorTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/cancelling_discriminator')
class StructuredPartialJoin(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/structured_partial_join')
class BlockingPartialJoin(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/blocking_partial_join')
class CancellingPartialJoin(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/cancelling_partial_join')
class GeneralizedAndJoin(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/generalized_and_join')
class LocalSynchronizingMergeTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/acyclic_synchronizing_merge')
class GeneralSynchronizingMergeTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/general_synchronizing_merge')
class ThreadMergeTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/thread_merge')
class ThreadSplitTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/thread_split')
class MultiInstanceWithoutSynchonizationTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/multi_instance_without_synch')
class MultiInstanceWithDesignTimeKnowledgeTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/multi_instance_with_a_priori_design_time_knowledge')
class MultiInstanceWithRunTimeKnowledgeTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/multi_instance_with_a_priori_run_time_knowledge')
class StaticPartialJoinMultiInstanceTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/static_partial_join_for_multi_instance')
class CancellingPartialJoinMultiInstanceTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/cancelling_partial_join_for_multi_instance')
class DynamicPartialJoinMultiInstanceTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/dynamic_partial_join_for_multi_instance')
class DeferredChoiceTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/deferred_choice')
class InterleavedParallelRoutingTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/interleaved_parallel_routing')
class MilestoneTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/milestone')
class CriticalSectionTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/critical_section')
class InterleavedRoutingTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/interleaved_routing')
class CancelTaskTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/cancel_task')
class CancelCaseTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/cancel_case')
class CancelRegionTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/cancel_region')
class CancelMultiInstanceTaskTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/cancel_multi_instance_task')
class CompleteMultiInstanceTaskTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/complete_multiple_instance_activity')
class ArbitraryCyclesTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/arbitrary_cycles')
class RecursionTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/recursion')
# I am disabling this test becuse I have wasted an entire day trying to make it pass
# The workflow completes and the task tree is as expected, but the subworkflow tasks
# no longer appear in the taken path. This is because they are connected to the subworkflow
# in on_reached_cb, which now occurs after they are executed.
# Moving subworkflow creation to predict would likely fix the problem, but there are problems
# with prediction that also need to be fixed as well.
#def test_run_workflow(self):
# pass
class ImplicitTerminationTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/implicit_termination')
class ExplicitTerminationTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/explicit_termination')
class TransientTriggerTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/transient_trigger')
class PersistentTriggerTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('control-flow/persistent_trigger')

View File

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
from unittest import TestCase
from .pattern_base import WorkflowPatternTestCase
class TaskDataTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('data/task_data')
class BlockDataTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('data/block_data')
class TaskToTaskTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('data/task_to_task')
class BlockToSubworkflowTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('data/block_to_subworkflow')
class SubworkflowTOBlockTest(TestCase, WorkflowPatternTestCase):
def setUp(self):
self.load_from_xml('data/subworkflow_to_block')

View File

@ -1,9 +1,5 @@
# -*- coding: utf-8 -*-
import sys
import unittest
import os.path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
from SpiffWorkflow.workflow import Workflow
from SpiffWorkflow.specs.Join import Join
@ -51,15 +47,15 @@ class PersistSmallWorkflowTest(unittest.TestCase):
tasks = workflow.get_tasks(TaskState.READY)
task_start = tasks[0]
workflow.complete_task_from_id(task_start.id)
workflow.run_task_from_id(task_start.id)
tasks = workflow.get_tasks(TaskState.READY)
multichoice = tasks[0]
workflow.complete_task_from_id(multichoice.id)
workflow.run_task_from_id(multichoice.id)
tasks = workflow.get_tasks(TaskState.READY)
task_a1 = tasks[0]
workflow.complete_task_from_id(task_a1.id)
workflow.run_task_from_id(task_a1.id)
return workflow
def testDictionarySerializer(self):
@ -104,7 +100,7 @@ class PersistSmallWorkflowTest(unittest.TestCase):
"""
old_workflow = self.workflow
old_workflow.complete_next()
old_workflow.run_next()
self.assertEqual('task_a2', old_workflow.last_task.get_name())
serializer = DictionarySerializer()
serialized_workflow = old_workflow.serialize(serializer)
@ -112,7 +108,7 @@ class PersistSmallWorkflowTest(unittest.TestCase):
serializer = DictionarySerializer()
new_workflow = Workflow.deserialize(serializer, serialized_workflow)
self.assertEqual('task_a2', old_workflow.last_task.get_name())
new_workflow.complete_all()
new_workflow.run_all()
self.assertEqual('task_a2', old_workflow.last_task.get_name())

View File

@ -69,7 +69,7 @@ class TaskTest(unittest.TestCase):
# Run the iterator test.
result = ''
for thetask in Task.Iterator(root, Task.MAYBE):
for thetask in Task.Iterator(root, TaskState.MAYBE):
result += thetask.get_dump(0, False) + '\n'
self.assertTrue(expected2.match(result),
'Expected:\n' + repr(expected2.pattern) + '\n' +

View File

@ -1,10 +1,7 @@
# -*- coding: utf-8 -*-
import sys
import unittest
import os
data_dir = os.path.join(os.path.dirname(__file__), 'data')
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
from lxml import etree
@ -15,6 +12,7 @@ from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec
from SpiffWorkflow.task import TaskState
from SpiffWorkflow.serializer.prettyxml import XmlSerializer
data_dir = os.path.join(os.path.dirname(__file__), 'data')
class WorkflowTest(unittest.TestCase):
@ -27,7 +25,7 @@ class WorkflowTest(unittest.TestCase):
"""
Simulates interactive calls, as would be issued by a user.
"""
xml_file = os.path.join(data_dir, 'spiff', 'workflow1.xml')
xml_file = os.path.join(data_dir, 'workflow1.xml')
with open(xml_file) as fp:
xml = etree.parse(fp).getroot()
wf_spec = WorkflowSpec.deserialize(XmlSerializer(), xml)
@ -36,7 +34,7 @@ class WorkflowTest(unittest.TestCase):
tasks = workflow.get_tasks(TaskState.READY)
self.assertEqual(len(tasks), 1)
self.assertEqual(tasks[0].task_spec.name, 'Start')
workflow.complete_task_from_id(tasks[0].id)
workflow.run_task_from_id(tasks[0].id)
self.assertEqual(tasks[0].state, TaskState.COMPLETED)
tasks = workflow.get_tasks(TaskState.READY)
@ -47,7 +45,7 @@ class WorkflowTest(unittest.TestCase):
self.assertEqual(task_a1.task_spec.name, 'task_a1')
self.assertEqual(task_b1.task_spec.__class__, Simple)
self.assertEqual(task_b1.task_spec.name, 'task_b1')
workflow.complete_task_from_id(task_a1.id)
workflow.run_task_from_id(task_a1.id)
self.assertEqual(task_a1.state, TaskState.COMPLETED)
tasks = workflow.get_tasks(TaskState.READY)
@ -56,16 +54,16 @@ class WorkflowTest(unittest.TestCase):
task_a2 = tasks[0]
self.assertEqual(task_a2.task_spec.__class__, Simple)
self.assertEqual(task_a2.task_spec.name, 'task_a2')
workflow.complete_task_from_id(task_a2.id)
workflow.run_task_from_id(task_a2.id)
tasks = workflow.get_tasks(TaskState.READY)
self.assertEqual(len(tasks), 1)
self.assertTrue(task_b1 in tasks)
workflow.complete_task_from_id(task_b1.id)
workflow.run_task_from_id(task_b1.id)
tasks = workflow.get_tasks(TaskState.READY)
self.assertEqual(len(tasks), 1)
workflow.complete_task_from_id(tasks[0].id)
workflow.run_task_from_id(tasks[0].id)
tasks = workflow.get_tasks(TaskState.READY)
self.assertEqual(len(tasks), 1)

View File

@ -0,0 +1,9 @@
Start
first
excl_choice_1
go_to_repetition
first
excl_choice_1
task_c1
last
End

View File

@ -0,0 +1,15 @@
Start
first
task_f1
struct_discriminator_1
excl_choice_1
first
task_f1
struct_discriminator_1
excl_choice_1
last
End
task_f2
task_f3
task_f2
task_f3

View File

@ -0,0 +1,15 @@
Start
multi_choice_1
task_e1
task_e3
struct_synch_merge_1
excl_choice_1
multi_choice_1
task_e1
task_e3
struct_synch_merge_1
excl_choice_1
last
End
task_e4
task_e4

View File

@ -0,0 +1,11 @@
Start
first
task_f1
struct_discriminator_1
excl_choice_1
first
task_f1
struct_discriminator_1
excl_choice_1
last
End

View File

@ -0,0 +1,13 @@
Start
multi_choice_1
task_e1
task_e3
struct_synch_merge_1
excl_choice_1
multi_choice_1
task_e1
task_e3
struct_synch_merge_1
excl_choice_1
last
End

View File

@ -10,20 +10,16 @@
<!-- Branch 1 -->
<task name="one_1">
<lock>lock_one</lock>
<successor>one_2</successor>
</task>
<acquire-mutex name="one_2" mutex="my_global_mutex">
<lock>lock_two</lock>
<successor>one_3</successor>
</acquire-mutex>
<task name="one_3">
<lock>lock_three</lock>
<successor>two_2</successor>
<successor>one_4</successor>
</task>
<release-mutex name="one_4" mutex="my_global_mutex">
<lock>lock_four</lock>
<successor>last</successor>
</release-mutex>
<!-- End branch 1 -->

Some files were not shown because too many files have changed in this diff Show More