spiff-arena/tests/SpiffWorkflow/bpmn/BpmnWorkflowSerializerTest.py
burnettk e53d860b40 Squashed 'SpiffWorkflow/' changes from a6392d1906..8d820dce1f
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
2022-11-04 09:33:42 -04:00

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())