spiff-arena/tests/SpiffWorkflow/util.py

115 lines
3.8 KiB
Python

# -*- coding: utf-8 -*-
import time
from SpiffWorkflow.task import Task, TaskState
from SpiffWorkflow.workflow import Workflow
def on_reached_cb(workflow, task, taken_path):
reached_key = "%s_reached" % str(task.get_name())
n_reached = task.get_data(reached_key, 0) + 1
task.set_data(**{reached_key: n_reached,
'two': 2,
'three': 3,
'test_attribute1': 'false',
'test_attribute2': 'true'})
# Collect a list of all data.
atts = []
for key, value in list(task.data.items()):
if key in ['data',
'two',
'three',
'test_attribute1',
'test_attribute2']:
continue
if key.endswith('reached'):
continue
atts.append('='.join((key, str(value))))
# Collect a list of all task data.
props = []
for key, value in list(task.task_spec.data.items()):
props.append('='.join((key, str(value))))
# Store the list of data in the workflow.
atts = ';'.join(atts)
props = ';'.join(props)
old = task.get_data('data', '')
data = task.get_name() + ': ' + atts + '/' + props + '\n'
task.set_data(data=old + data)
# In workflows that load a subworkflow, the newly loaded children
# will not have on_reached_cb() assigned. By using this function, we
# re-assign the function in every step, thus making sure that new
# children also call on_reached_cb().
for child in task.children:
track_task(child.task_spec, taken_path)
return True
def on_complete_cb(workflow, task, taken_path):
# Record the path.
indent = ' ' * (task._get_depth() - 1)
taken_path.append('%s%s' % (indent, task.get_name()))
return True
def track_task(task_spec, taken_path):
if task_spec.reached_event.is_connected(on_reached_cb):
task_spec.reached_event.disconnect(on_reached_cb)
task_spec.reached_event.connect(on_reached_cb, taken_path)
if task_spec.completed_event.is_connected(on_complete_cb):
task_spec.completed_event.disconnect(on_complete_cb)
task_spec.completed_event.connect(on_complete_cb, taken_path)
def track_workflow(wf_spec, taken_path=None):
if taken_path is None:
taken_path = []
for name in wf_spec.task_specs:
track_task(wf_spec.task_specs[name], taken_path)
return taken_path
def run_workflow(test, wf_spec, expected_path, expected_data, workflow=None):
# Execute all tasks within the Workflow.
if workflow is None:
taken_path = track_workflow(wf_spec)
workflow = Workflow(wf_spec)
else:
taken_path = track_workflow(workflow.spec)
test.assertFalse(workflow.is_completed())
try:
# We allow the workflow to require a maximum of 5 seconds to
# complete, to allow for testing long running tasks.
for i in range(10):
workflow.complete_all(False)
if workflow.is_completed():
break
time.sleep(0.5)
except:
workflow.task_tree.dump()
raise
# workflow.task_tree.dump()
test.assertTrue(workflow.is_completed(), workflow.task_tree.get_dump())
# Make sure that there are no waiting tasks left in the tree.
for thetask in Task.Iterator(workflow.task_tree, TaskState.READY):
workflow.task_tree.dump()
raise Exception('Task with state READY: %s' % thetask.name)
# Check whether the correct route was taken.
if expected_path is not None:
taken_path = '\n'.join(taken_path) + '\n'
test.assertEqual(taken_path, expected_path)
# Check data availibility.
if expected_data is not None:
result = workflow.get_data('data', '')
test.assertIn(result, expected_data)
return workflow