mirror of
https://github.com/sartography/spiff-arena.git
synced 2025-01-15 20:14:56 +00:00
e53d860b40
8d820dce1f Track spiff step details more granularly (#17) 426da26d8f Clear the remaining __init__.py imports in SpiffWorkflow (#14) 9a1d1c484a Fix FutureWarning in SpiffWorkflow (#16) git-subtree-dir: SpiffWorkflow git-subtree-split: 8d820dce1f439bb76bc07e39629832d998d6f634
217 lines
9.3 KiB
Python
217 lines
9.3 KiB
Python
import os
|
|
import unittest
|
|
import json
|
|
from uuid import uuid4
|
|
|
|
from SpiffWorkflow.task import TaskState
|
|
from SpiffWorkflow.bpmn.PythonScriptEngine import PythonScriptEngine
|
|
from SpiffWorkflow.bpmn.parser.BpmnParser import BpmnParser
|
|
from SpiffWorkflow.bpmn.serializer.workflow import BpmnWorkflowSerializer
|
|
from SpiffWorkflow.bpmn.serializer.BpmnSerializer import BpmnSerializer
|
|
from SpiffWorkflow.bpmn.workflow import BpmnWorkflow
|
|
from tests.SpiffWorkflow.bpmn.BpmnLoaderForTests import TestUserTaskConverter
|
|
|
|
|
|
class BpmnWorkflowSerializerTest(unittest.TestCase):
|
|
"""Please note that the BpmnSerializer is Deprecated."""
|
|
SERIALIZER_VERSION = "100.1.ANY"
|
|
|
|
def load_workflow_spec(self, filename, process_name):
|
|
f = os.path.join(os.path.dirname(__file__), 'data', filename)
|
|
parser = BpmnParser()
|
|
parser.add_bpmn_files_by_glob(f)
|
|
top_level_spec = parser.get_spec(process_name)
|
|
subprocesses = parser.get_subprocess_specs(process_name)
|
|
return top_level_spec, subprocesses
|
|
|
|
def setUp(self):
|
|
super(BpmnWorkflowSerializerTest, self).setUp()
|
|
wf_spec_converter = BpmnWorkflowSerializer.configure_workflow_spec_converter([TestUserTaskConverter])
|
|
self.serializer = BpmnWorkflowSerializer(wf_spec_converter, version=self.SERIALIZER_VERSION)
|
|
spec, subprocesses = self.load_workflow_spec('random_fact.bpmn', 'random_fact')
|
|
self.workflow = BpmnWorkflow(spec, subprocesses)
|
|
|
|
def testSerializeWorkflowSpec(self):
|
|
spec_serialized = self.serializer.serialize_json(self.workflow)
|
|
result = self.serializer.deserialize_json(spec_serialized)
|
|
spec_serialized2 = self.serializer.serialize_json(result)
|
|
self.assertEqual(spec_serialized, spec_serialized2)
|
|
|
|
def testSerializeWorkflowSpecWithGzip(self):
|
|
spec_serialized = self.serializer.serialize_json(self.workflow, use_gzip=True)
|
|
result = self.serializer.deserialize_json(spec_serialized, use_gzip=True)
|
|
spec_serialized2 = self.serializer.serialize_json(result, use_gzip=True)
|
|
self.assertEqual(spec_serialized, spec_serialized2)
|
|
|
|
def testSerlializePerservesVersion(self):
|
|
spec_serialized = self.serializer.serialize_json(self.workflow)
|
|
version = self.serializer.get_version(spec_serialized)
|
|
self.assertEqual(version, self.SERIALIZER_VERSION)
|
|
|
|
def testSerializeToOldSerializerThenNewSerializer(self):
|
|
old_serializer = BpmnSerializer()
|
|
old_json = old_serializer.serialize_workflow(self.workflow)
|
|
new_workflow = old_serializer.deserialize_workflow(old_json)
|
|
new_json = self.serializer.serialize_json(new_workflow)
|
|
new_workflow_2 = self.serializer.deserialize_json(new_json)
|
|
|
|
def testSerializeWorkflow(self):
|
|
serialized = self.serializer.serialize_json(self.workflow)
|
|
json.loads(serialized)
|
|
|
|
def testSerializeWorkflowCustomJSONEncoderDecoder(self):
|
|
class MyCls:
|
|
a = 1
|
|
def to_dict(self):
|
|
return {'a': 1, 'my_type': 'mycls'}
|
|
|
|
@classmethod
|
|
def from_dict(self, data):
|
|
return MyCls()
|
|
|
|
class MyJsonEncoder(json.JSONEncoder):
|
|
def default(self, z):
|
|
if isinstance(z, MyCls):
|
|
return z.to_dict()
|
|
return super().default(z)
|
|
|
|
class MyJsonDecoder(json.JSONDecoder):
|
|
classes = {'mycls': MyCls}
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(object_hook=self.object_hook, *args, **kwargs)
|
|
|
|
def object_hook(self, z):
|
|
if 'my_type' in z and z['my_type'] in self.classes:
|
|
return self.classes[z['my_type']].from_dict(z)
|
|
|
|
return z
|
|
|
|
unserializable = MyCls()
|
|
|
|
a_task_spec = self.workflow.spec.task_specs[list(self.workflow.spec.task_specs)[0]]
|
|
a_task = self.workflow.get_tasks_from_spec_name(a_task_spec.name)[0]
|
|
a_task.data['jsonTest'] = unserializable
|
|
|
|
try:
|
|
self.assertRaises(TypeError, self.serializer.serialize_json, self.workflow)
|
|
wf_spec_converter = BpmnWorkflowSerializer.configure_workflow_spec_converter([TestUserTaskConverter])
|
|
custom_serializer = BpmnWorkflowSerializer(wf_spec_converter, version=self.SERIALIZER_VERSION,json_encoder_cls=MyJsonEncoder, json_decoder_cls=MyJsonDecoder)
|
|
serialized_workflow = custom_serializer.serialize_json(self.workflow)
|
|
finally:
|
|
a_task.data.pop('jsonTest',None)
|
|
|
|
serialized_task = [x for x in json.loads(serialized_workflow)['tasks'].values() if x['task_spec'] == a_task_spec.name][0]
|
|
self.assertEqual(serialized_task['data']['jsonTest'], {'a': 1, 'my_type': 'mycls'})
|
|
|
|
deserialized_workflow = custom_serializer.deserialize_json(serialized_workflow)
|
|
deserialized_task = deserialized_workflow.get_tasks_from_spec_name(a_task_spec.name)[0]
|
|
self.assertTrue(isinstance(deserialized_task.data['jsonTest'], MyCls))
|
|
|
|
def testDeserializeWorkflow(self):
|
|
self._compare_with_deserialized_copy(self.workflow)
|
|
|
|
def testSerializeTask(self):
|
|
self.serializer.serialize_json(self.workflow)
|
|
|
|
def testDeserializeTask(self):
|
|
self._compare_with_deserialized_copy(self.workflow)
|
|
|
|
def testDeserializeActiveWorkflow(self):
|
|
self.workflow.do_engine_steps()
|
|
self._compare_with_deserialized_copy(self.workflow)
|
|
|
|
def testDeserializeWithData(self):
|
|
self.workflow.data["test"] = "my_test"
|
|
json = self.serializer.serialize_json(self.workflow)
|
|
wf2 = self.serializer.deserialize_json(json)
|
|
self.assertEqual('my_test', wf2.get_data("test"))
|
|
|
|
def testDeserializeWithDefaultScriptEngineClass(self):
|
|
json = self.serializer.serialize_json(self.workflow)
|
|
wf2 = self.serializer.deserialize_json(json)
|
|
self.assertIsNotNone(self.workflow.script_engine)
|
|
self.assertIsNotNone(wf2.script_engine)
|
|
self.assertEqual(self.workflow.script_engine.__class__,
|
|
wf2.script_engine.__class__)
|
|
|
|
@unittest.skip("Deserialize does not persist the script engine, Fix me.")
|
|
def testDeserializeWithCustomScriptEngine(self):
|
|
class CustomScriptEngine(PythonScriptEngine):
|
|
pass
|
|
|
|
self.workflow.script_engine = CustomScriptEngine()
|
|
dct = self.serializer.serialize_json(self.workflow)
|
|
wf2 = self.serializer.deserialize_json(dct)
|
|
self.assertEqual(self.workflow.script_engine.__class__,
|
|
wf2.script_engine.__class__)
|
|
|
|
def testDeserializeWithDataOnTask(self):
|
|
self.workflow.do_engine_steps()
|
|
user_task = self.workflow.get_ready_user_tasks()[0]
|
|
user_task.data = {"test":"my_test"}
|
|
self._compare_with_deserialized_copy(self.workflow)
|
|
|
|
def testSerializeIgnoresCallable(self):
|
|
self.workflow.do_engine_steps()
|
|
user_task = self.workflow.get_ready_user_tasks()[0]
|
|
def f(n):
|
|
return n + 1
|
|
user_task.data = { 'f': f }
|
|
task_id = str(user_task.id)
|
|
dct = self.serializer.workflow_to_dict(self.workflow)
|
|
self.assertNotIn('f', dct['tasks'][task_id]['data'])
|
|
|
|
def testLastTaskIsSetAndWorksThroughRestore(self):
|
|
self.workflow.do_engine_steps()
|
|
json = self.serializer.serialize_json(self.workflow)
|
|
wf2 = self.serializer.deserialize_json(json)
|
|
self.assertIsNotNone(self.workflow.last_task)
|
|
self.assertIsNotNone(wf2.last_task)
|
|
self._compare_workflows(self.workflow, wf2)
|
|
|
|
def test_convert_1_0_to_1_1(self):
|
|
# The serialization used here comes from NestedSubprocessTest saved at line 25 with version 1.0
|
|
fn = os.path.join(os.path.dirname(__file__), 'data', 'serialization', 'v1.0.json')
|
|
wf = self.serializer.deserialize_json(open(fn).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()
|
|
wf.do_engine_steps()
|
|
self.assertEqual(True, wf.is_completed())
|
|
|
|
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()
|
|
self.workflow.do_engine_steps()
|
|
results = self.serializer.serialize_json(self.workflow)
|
|
assert self.workflow.is_completed()
|
|
assert 'y' in self.workflow.last_task.data
|
|
assert 'x' not in self.workflow.last_task.data
|
|
assert 'some_fun' not in self.workflow.last_task.data
|
|
|
|
def _compare_with_deserialized_copy(self, wf):
|
|
json = self.serializer.serialize_json(wf)
|
|
wf2 = self.serializer.deserialize_json(json)
|
|
self._compare_workflows(wf, wf2)
|
|
|
|
def _compare_workflows(self, w1, w2):
|
|
self.assertIsInstance(w1, BpmnWorkflow)
|
|
self.assertIsInstance(w2, BpmnWorkflow)
|
|
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)
|
|
self.assertIsNotNone(w2_task)
|
|
self.assertEqual(task.data, w2_task.data)
|
|
|
|
|
|
def suite():
|
|
return unittest.TestLoader().loadTestsFromTestCase(BpmnWorkflowSerializerTest)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.TextTestRunner(verbosity=2).run(suite())
|