diff --git a/doc/errors.rst b/doc/errors.rst new file mode 100644 index 00000000..31c606de --- /dev/null +++ b/doc/errors.rst @@ -0,0 +1,90 @@ +SpiffWorkflow Exceptions +==================================== +Details about the exceptions and exception hierarchy within SpiffWorkflow + +SpiffWorkflowException +---------- +Base exception for all exceptions raised by SpiffWorkflow + +ValidationException +---------- + +**Extends** +SpiffWorkflowException + +Thrown during the parsing of a workflow. + +**Attributes/Methods** + +- **tag**: The type of xml tag being parsed +- **id**: the id attribute of the xml tag, if available. +- **name**: the name attribute of the xml tag, if available. +- **line_number**: the line number where the tag occurs. +- **file_name**: The name of the file where the error occurred. +- **message**: a human readable error message. + + +WorkflowException +-------- +When an error occurs with a Task Specification (maybe should have been called +a SpecException) + +**Extends** +SpiffWorkflowException + +**Attributes/Methods** + +- **sender**: The TaskSpec - the specific Task, Gateway, etc... that caused the error to happen. +- **error**: a human readable error message describing the problem. +- **get_task_trace**: Provided a specific Task, will work it's way through the workflow / sub-processes +and call activities to show where an error occurred. Useful if the error happened within a deeply nested structure (where call activities include call activities ....) + +WorkflowDataException +------------------ +When an exception occurs moving data between tasks and Data Objects (including +data inputs and data outputs.) + +**Extends** +WorkflowException + +**Attributes/Methods** + +(in addition to the values in a WorkflowException) + + - **task**: The specific task (not the task spec, but the actual executing task) + - **data_input**: The spec of the input variable + - **data_output**: The spec of the output variable + +WorkflowTaskException +-------- +**Extends** +WorkflowException + +**Attributes/Methods** + +(in addition to the values in a WorkflowException) + + - **task**: The specific task (not the task spec, but the actual executing task) + - **error_msg**: The detailed human readable message. (conflicts with error above) + - **exception**: The original exception this wraps around. + - **line_number** The line number that contains the error + - **offset** The point in the line that caused the error + - **error_line** The content of the line that caused the error. + +It will accept the line_number and error_line as arguments - if the +underlying error provided is a SyntaxError it will try to derive this +information from the error. +If this is a name error, it will attempt to calculate a did-you-mean +error_msg. + +Unused / Deprecated errors +-------------------- + +** StorageException ** +Deprecated -- Used only by the PrettyXmlSerializer - which is not under active +support. + +** DeadMethodCalled ** +Something related to WeakMethod -- which doesn't look to be utilized anymore. + + diff --git a/graphics/spiffworkflow_logo_ideas.svg b/graphics/spiffworkflow_logo_ideas.svg index 28e5d8ac..b51b8b52 100644 --- a/graphics/spiffworkflow_logo_ideas.svg +++ b/graphics/spiffworkflow_logo_ideas.svg @@ -26,13 +26,13 @@ showgrid="false" showguides="true" inkscape:guide-bbox="true" - inkscape:zoom="0.27433373" - inkscape:cx="-586.87643" - inkscape:cy="1882.7433" + inkscape:zoom="1.5518659" + inkscape:cx="2265.0153" + inkscape:cy="3541.2209" inkscape:window-width="1916" - inkscape:window-height="1076" + inkscape:window-height="916" inkscape:window-x="0" - inkscape:window-y="0" + inkscape:window-y="162" inkscape:window-maximized="1" inkscape:current-layer="layer1"> + + + @@ -839,6 +851,91 @@ x="-580.08496" y="716.69928">Draw the code + + + + + + + + + + + + + + + + + + Draw the code + + + + + diff --git a/tests/SpiffWorkflow/bpmn/ApprovalsTest.py b/tests/SpiffWorkflow/bpmn/ApprovalsTest.py index 7576a23f..857c81f0 100644 --- a/tests/SpiffWorkflow/bpmn/ApprovalsTest.py +++ b/tests/SpiffWorkflow/bpmn/ApprovalsTest.py @@ -2,7 +2,6 @@ import unittest from SpiffWorkflow.bpmn.workflow import BpmnWorkflow -from SpiffWorkflow.bpmn.specs.events.event_definitions import MessageEventDefinition from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase __author__ = 'matth' @@ -86,8 +85,7 @@ class ApprovalsTest(BpmnWorkflowTestCase): self.save_restore() self.do_next_named_step('Parallel_Approvals_SP.Manager_Approval') self.do_next_exclusive_step('Parallel_Approvals_SP.Step1') - self.do_next_exclusive_step( - 'Parallel_Approvals_SP.Supervisor_Approval') + self.do_next_exclusive_step('Parallel_Approvals_SP.Supervisor_Approval') self.do_next_exclusive_step('Approvals.Parallel_SP_Done') def testSaveRestoreWaiting(self): @@ -108,93 +106,10 @@ class ApprovalsTest(BpmnWorkflowTestCase): self.save_restore() self.do_next_exclusive_step('Parallel_Approvals_SP.Step1') self.save_restore() - self.do_next_exclusive_step( - 'Parallel_Approvals_SP.Supervisor_Approval') + self.do_next_exclusive_step('Parallel_Approvals_SP.Supervisor_Approval') self.save_restore() self.do_next_exclusive_step('Approvals.Parallel_SP_Done') - def testReadonlyWaiting(self): - - self.do_next_named_step('First_Approval_Wins.Manager_Approval') - - readonly = self.get_read_only_workflow() - self.assertEqual(1, len(readonly.get_ready_user_tasks())) - self.assertEqual('Approvals.First_Approval_Wins_Done', - readonly.get_ready_user_tasks()[0].task_spec.name) - self.assertRaises(AssertionError, readonly.do_engine_steps) - self.assertRaises(AssertionError, readonly.refresh_waiting_tasks) - self.assertRaises(AssertionError, readonly.catch, MessageEventDefinition('Cheese')) - self.assertRaises( - AssertionError, readonly.get_ready_user_tasks()[0].complete) - - self.do_next_exclusive_step('Approvals.First_Approval_Wins_Done') - - readonly = self.get_read_only_workflow() - self.assertEqual(2, len(readonly.get_ready_user_tasks())) - self.assertEqual( - ['Approvals.Manager_Approval__P_', - 'Approvals.Supervisor_Approval__P_'], - sorted(t.task_spec.name for t in readonly.get_ready_user_tasks())) - self.assertRaises( - AssertionError, readonly.get_ready_user_tasks()[0].complete) - - self.do_next_named_step('Approvals.Supervisor_Approval__P_') - - readonly = self.get_read_only_workflow() - self.assertEqual(1, len(readonly.get_ready_user_tasks())) - self.assertEqual('Approvals.Manager_Approval__P_', - readonly.get_ready_user_tasks()[0].task_spec.name) - self.assertRaises( - AssertionError, readonly.get_ready_user_tasks()[0].complete) - self.do_next_named_step('Approvals.Manager_Approval__P_') - - readonly = self.get_read_only_workflow() - self.assertEqual(1, len(readonly.get_ready_user_tasks())) - self.assertEqual('Approvals.Parallel_Approvals_Done', - readonly.get_ready_user_tasks()[0].task_spec.name) - self.assertRaises( - AssertionError, readonly.get_ready_user_tasks()[0].complete) - self.do_next_exclusive_step('Approvals.Parallel_Approvals_Done') - - readonly = self.get_read_only_workflow() - self.assertEqual(2, len(readonly.get_ready_user_tasks())) - self.assertEqual( - ['Parallel_Approvals_SP.Manager_Approval', - 'Parallel_Approvals_SP.Step1'], - sorted(t.task_spec.name for t in readonly.get_ready_user_tasks())) - self.assertRaises( - AssertionError, readonly.get_ready_user_tasks()[0].complete) - self.do_next_named_step('Parallel_Approvals_SP.Manager_Approval') - - readonly = self.get_read_only_workflow() - self.assertEqual(1, len(readonly.get_ready_user_tasks())) - self.assertEqual('Parallel_Approvals_SP.Step1', - readonly.get_ready_user_tasks()[0].task_spec.name) - self.assertRaises( - AssertionError, readonly.get_ready_user_tasks()[0].complete) - self.do_next_exclusive_step('Parallel_Approvals_SP.Step1') - - readonly = self.get_read_only_workflow() - self.assertEqual(1, len(readonly.get_ready_user_tasks())) - self.assertEqual('Parallel_Approvals_SP.Supervisor_Approval', - readonly.get_ready_user_tasks()[0].task_spec.name) - self.assertRaises( - AssertionError, readonly.get_ready_user_tasks()[0].complete) - self.do_next_exclusive_step( - 'Parallel_Approvals_SP.Supervisor_Approval') - - readonly = self.get_read_only_workflow() - self.assertEqual(1, len(readonly.get_ready_user_tasks())) - self.assertEqual('Approvals.Parallel_SP_Done', - readonly.get_ready_user_tasks()[0].task_spec.name) - self.assertRaises( - AssertionError, readonly.get_ready_user_tasks()[0].complete) - self.do_next_exclusive_step('Approvals.Parallel_SP_Done') - - readonly = self.get_read_only_workflow() - self.assertEqual(0, len(readonly.get_ready_user_tasks())) - self.assertEqual(0, len(readonly.get_waiting_tasks())) - def suite(): return unittest.TestLoader().loadTestsFromTestCase(ApprovalsTest) diff --git a/tests/SpiffWorkflow/bpmn/BpmnSerializerTest.py b/tests/SpiffWorkflow/bpmn/BpmnSerializerTest.py deleted file mode 100644 index a8b6ebd5..00000000 --- a/tests/SpiffWorkflow/bpmn/BpmnSerializerTest.py +++ /dev/null @@ -1,118 +0,0 @@ -import os -import unittest - -from SpiffWorkflow.bpmn.PythonScriptEngine import PythonScriptEngine -from SpiffWorkflow.bpmn.serializer.BpmnSerializer import BpmnSerializer -from SpiffWorkflow.bpmn.workflow import BpmnWorkflow -from .BpmnLoaderForTests import TestBpmnParser - - -class BpmnSerializerTest(unittest.TestCase): - CORRELATE = BpmnSerializer - - def load_workflow_spec(self, filename, process_name): - f = os.path.join(os.path.dirname(__file__), 'data', filename) - parser = TestBpmnParser() - 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(BpmnSerializerTest, self).setUp() - self.serializer = BpmnSerializer() - self.spec, subprocesses = self.load_workflow_spec('random_fact.bpmn', 'random_fact') - self.workflow = BpmnWorkflow(self.spec, subprocesses) - - def testDeserializeWorkflowSpec(self): - self.assertIsNotNone(self.spec) - - def testSerializeWorkflowSpec(self): - spec_serialized = self.serializer.serialize_workflow_spec(self.spec) - result = self.serializer.deserialize_workflow_spec(spec_serialized) - spec_serialized2 = self.serializer.serialize_workflow_spec(result) - self.assertEqual(spec_serialized, spec_serialized2) - - def testSerializeWorkflow(self): - json = self.serializer.serialize_workflow(self.workflow) - print(json) - - def testDeserializeWorkflow(self): - self._compare_with_deserialized_copy(self.workflow) - - def testDeserializeCallActivityChildren(self): - """Tested as a part of deserialize workflow.""" - pass - - def testSerializeTask(self): - json = self.serializer.serialize_workflow(self.workflow) - print(json) - - 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_workflow(self.workflow) - wf2 = self.serializer.deserialize_workflow(json, workflow_spec=self.spec) - self.assertEqual('my_test', wf2.get_data("test")) - - def testDeserializeWithDefaultScriptEngineClass(self): - json = self.serializer.serialize_workflow(self.workflow) - wf2 = self.serializer.deserialize_workflow(json, workflow_spec=self.spec) - 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() - json = self.serializer.serialize_workflow(self.workflow) - wf2 = self.serializer.deserialize_workflow(json, workflow_spec=self.spec) - 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 testLastTaskIsSetAndWorksThroughRestore(self): - self.workflow.do_engine_steps() - json = self.serializer.serialize_workflow(self.workflow) - wf2 = self.serializer.deserialize_workflow(json, workflow_spec=self.spec) - self.assertIsNotNone(self.workflow.last_task) - self.assertIsNotNone(wf2.last_task) - self._compare_workflows(self.workflow, wf2) - - def _compare_with_deserialized_copy(self, wf): - json = self.serializer.serialize_workflow(wf) - wf2 = self.serializer.deserialize_workflow(json, workflow_spec=self.spec) - 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(BpmnSerializerTest) - - -if __name__ == '__main__': - unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/tests/SpiffWorkflow/bpmn/BpmnWorkflowSerializerTest.py b/tests/SpiffWorkflow/bpmn/BpmnWorkflowSerializerTest.py index ac2ae463..e5b77156 100644 --- a/tests/SpiffWorkflow/bpmn/BpmnWorkflowSerializerTest.py +++ b/tests/SpiffWorkflow/bpmn/BpmnWorkflowSerializerTest.py @@ -1,13 +1,11 @@ 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 @@ -48,13 +46,6 @@ class BpmnWorkflowSerializerTest(unittest.TestCase): 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) diff --git a/tests/SpiffWorkflow/bpmn/BpmnWorkflowTestCase.py b/tests/SpiffWorkflow/bpmn/BpmnWorkflowTestCase.py index 9b7865bd..8f2f0af5 100644 --- a/tests/SpiffWorkflow/bpmn/BpmnWorkflowTestCase.py +++ b/tests/SpiffWorkflow/bpmn/BpmnWorkflowTestCase.py @@ -122,7 +122,7 @@ class BpmnWorkflowTestCase(unittest.TestCase): before_dump = self.workflow.get_dump() # Check that we can actully convert this to JSON json_str = json.dumps(before_state) - after = self.serializer.workflow_from_dict(json.loads(json_str), read_only=False) + after = self.serializer.workflow_from_dict(json.loads(json_str)) # Check that serializing and deserializing results in the same workflow after_state = self.serializer.workflow_to_dict(after) after_dump = after.get_dump() @@ -132,11 +132,7 @@ class BpmnWorkflowTestCase(unittest.TestCase): self.workflow = after def restore(self, state): - self.workflow = self.serializer.workflow_from_dict(state, read_only=False) - - def get_read_only_workflow(self): - state = self._get_workflow_state() - return self.serializer.workflow_from_dict(state, read_only=True) + self.workflow = self.serializer.workflow_from_dict(state) def _get_workflow_state(self, do_steps=True): if do_steps: diff --git a/tests/SpiffWorkflow/bpmn/CallActivityEndEventTest.py b/tests/SpiffWorkflow/bpmn/CallActivityEndEventTest.py index f3d1522d..1e3d158e 100644 --- a/tests/SpiffWorkflow/bpmn/CallActivityEndEventTest.py +++ b/tests/SpiffWorkflow/bpmn/CallActivityEndEventTest.py @@ -3,9 +3,9 @@ import unittest from SpiffWorkflow.bpmn.PythonScriptEngine import PythonScriptEngine -from SpiffWorkflow.bpmn.exceptions import WorkflowTaskExecException from SpiffWorkflow.bpmn.workflow import BpmnWorkflow +from SpiffWorkflow.exceptions import WorkflowTaskException from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase __author__ = 'kellym' @@ -60,7 +60,7 @@ class CallActivityTest(BpmnWorkflowTestCase): def test_call_acitivity_errors_include_task_trace(self): error_spec = self.subprocesses.get('ErroringBPMN') error_spec, subprocesses = self.load_workflow_spec('call_activity_*.bpmn', 'ErroringBPMN') - with self.assertRaises(WorkflowTaskExecException) as context: + with self.assertRaises(WorkflowTaskException) as context: self.workflow = BpmnWorkflow(error_spec, subprocesses) self.workflow.do_engine_steps() self.assertEquals(2, len(context.exception.task_trace)) diff --git a/tests/SpiffWorkflow/bpmn/CustomScriptTest.py b/tests/SpiffWorkflow/bpmn/CustomScriptTest.py index 12f69a2a..8cbca47f 100644 --- a/tests/SpiffWorkflow/bpmn/CustomScriptTest.py +++ b/tests/SpiffWorkflow/bpmn/CustomScriptTest.py @@ -1,10 +1,10 @@ # -*- coding: utf-8 -*- import unittest +from SpiffWorkflow.exceptions import WorkflowTaskException from SpiffWorkflow.task import TaskState from SpiffWorkflow.bpmn.PythonScriptEngine import PythonScriptEngine from SpiffWorkflow.bpmn.workflow import BpmnWorkflow -from SpiffWorkflow.bpmn.exceptions import WorkflowTaskExecException from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase __author__ = 'McDonald, danfunk' @@ -46,7 +46,7 @@ class CustomInlineScriptTest(BpmnWorkflowTestCase): def test_overwrite_function_with_local_variable(self): ready_task = self.workflow.get_tasks(TaskState.READY)[0] ready_task.data = {'custom_function': "bill"} - with self.assertRaises(WorkflowTaskExecException) as e: + with self.assertRaises(WorkflowTaskException) as e: self.workflow.do_engine_steps() self.assertTrue('' in str(e.exception)) self.assertTrue('custom_function' in str(e.exception)) diff --git a/tests/SpiffWorkflow/bpmn/InvalidWorkflowsTest.py b/tests/SpiffWorkflow/bpmn/InvalidWorkflowsTest.py index ffb8f024..9987567a 100644 --- a/tests/SpiffWorkflow/bpmn/InvalidWorkflowsTest.py +++ b/tests/SpiffWorkflow/bpmn/InvalidWorkflowsTest.py @@ -31,18 +31,11 @@ class InvalidWorkflowsTest(BpmnWorkflowTestCase): except ValidationException as ex: self.assertTrue('No start event found' in ('%r' % ex), '\'No start event found\' should be a substring of error message: \'%r\'' % ex) - self.assertTrue('No-Start-Event.bpmn20.xml' in ('%r' % ex), + self.assertTrue('No-Start-Event.bpmn20.xml' in ex.file_name, '\'No-Start-Event.bpmn20.xml\' should be a substring of error message: \'%r\'' % ex) - self.assertTrue('process' in ('%r' % ex), - '\'process\' should be a substring of error message: \'%r\'' % ex) - self.assertTrue( - 'sid-669ddebf-4196-41ee-8b04-bcc90bc5f983' in ('%r' % ex), - '\'sid-669ddebf-4196-41ee-8b04-bcc90bc5f983\' should be a substring of error message: \'%r\'' % ex) - self.assertTrue('No Start Event' in ('%r' % ex), - '\'No Start Event\' should be a substring of error message: \'%r\'' % ex) def testSubprocessNotFound(self): - + with self.assertRaises(ValidationException) as exc: self.load_workflow_spec('Invalid-Workflows/Subprocess-Not-Found.bpmn20.xml', 'Subprocess Not Found') self.assertIn("The process 'Missing subprocess' was not found.", str(exc)) @@ -60,15 +53,12 @@ class InvalidWorkflowsTest(BpmnWorkflowTestCase): 'There is no support implemented for this task type' in ( '%r' % ex), '\'There is no support implemented for this task type\' should be a substring of error message: \'%r\'' % ex) - self.assertTrue('Unsupported-Task.bpmn20.xml' in ('%r' % ex), + self.assertTrue('Unsupported-Task.bpmn20.xml' in ex.file_name, '\'Unsupported-Task.bpmn20.xml\' should be a substring of error message: \'%r\'' % ex) - self.assertTrue('businessRuleTask' in ('%r' % ex), - '\'businessRuleTask\' should be a substring of error message: \'%r\'' % ex) - self.assertTrue( - 'sid-75EEAB28-3B69-4282-B91A-0F3C97931834' in ('%r' % ex), - '\'sid-75EEAB28-3B69-4282-B91A-0F3C97931834\' should be a substring of error message: \'%r\'' % ex) - self.assertTrue('Business Rule Task' in ('%r' % ex), - '\'Business Rule Task\' should be a substring of error message: \'%r\'' % ex) + self.assertTrue('businessRuleTask' in ex.tag, + '\'businessRuleTask\' should be a substring of the tag: \'%r\'' % ex) + self.assertTrue('Business Rule Task' in ex.name, + '\'Business Rule Task\' should be the name: \'%s\'' % ex.name) def suite(): diff --git a/tests/SpiffWorkflow/bpmn/ParserTest.py b/tests/SpiffWorkflow/bpmn/ParserTest.py index 5703273e..59a32775 100644 --- a/tests/SpiffWorkflow/bpmn/ParserTest.py +++ b/tests/SpiffWorkflow/bpmn/ParserTest.py @@ -1,7 +1,8 @@ import unittest import os -from SpiffWorkflow.bpmn.parser.BpmnParser import BpmnParser +from SpiffWorkflow.bpmn.parser.BpmnParser import BpmnParser, BpmnValidator +from SpiffWorkflow.bpmn.parser.ValidationException import ValidationException class ParserTest(unittest.TestCase): @@ -27,3 +28,17 @@ class ParserTest(unittest.TestCase): self.assertEqual(generate.data_output_associations[0].name, 'obj_1') self.assertEqual(len(read.data_input_associations), 1) self.assertEqual(read.data_input_associations[0].name, 'obj_1') + + def testValidatorError(self): + parser = BpmnParser(validator=BpmnValidator()) + bpmn_file = os.path.join(os.path.dirname(__file__), 'data', + 'data_object_invalid.bpmn') + errored = False + try: + parser.add_bpmn_file(bpmn_file) + except ValidationException as ex: + errored = True + self.assertEqual(ex.file_name, bpmn_file) + self.assertEqual(14, ex.line_number) + self.assertIn('DataObjectReference_0cm8dnh', str(ex)) + assert(errored, "This should have errored out with a validation exception.") diff --git a/tests/SpiffWorkflow/bpmn/ScriptTest.py b/tests/SpiffWorkflow/bpmn/ScriptTest.py index efe9f1c8..da0a4a29 100644 --- a/tests/SpiffWorkflow/bpmn/ScriptTest.py +++ b/tests/SpiffWorkflow/bpmn/ScriptTest.py @@ -2,7 +2,7 @@ import unittest -from SpiffWorkflow.bpmn.exceptions import WorkflowTaskExecException +from SpiffWorkflow.exceptions import WorkflowTaskException from SpiffWorkflow.task import TaskState from SpiffWorkflow.bpmn.workflow import BpmnWorkflow from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase @@ -39,7 +39,7 @@ class InlineScriptTest(BpmnWorkflowTestCase): # StartTask doesn't know about testvar, it happened earlier. # calling an exec that references testvar, in the context of the # start task should fail. - with self.assertRaises(WorkflowTaskExecException): + with self.assertRaises(WorkflowTaskException): result = self.workflow.script_engine.evaluate(startTask, 'testvar == True') diff --git a/tests/SpiffWorkflow/bpmn/ServiceTaskTest.py b/tests/SpiffWorkflow/bpmn/ServiceTaskTest.py index 29060708..a0112efe 100644 --- a/tests/SpiffWorkflow/bpmn/ServiceTaskTest.py +++ b/tests/SpiffWorkflow/bpmn/ServiceTaskTest.py @@ -8,16 +8,15 @@ sys.path.insert(0, os.path.join(dirname, '..', '..', '..')) from SpiffWorkflow.bpmn.PythonScriptEngine import PythonScriptEngine from SpiffWorkflow.bpmn.workflow import BpmnWorkflow -from SpiffWorkflow.bpmn.exceptions import WorkflowTaskExecException from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase class ServiceTaskTest(BpmnWorkflowTestCase): def setUp(self): - spec, subprocesses = self.load_workflow_spec('service_task.bpmn', + spec, subprocesses = self.load_workflow_spec('service_task.bpmn', 'service_task_example1') - self.workflow = BpmnWorkflow(spec, subprocesses) + self.workflow = BpmnWorkflow(spec, subprocesses) def testRunThroughHappy(self): self.workflow.do_engine_steps() diff --git a/tests/SpiffWorkflow/bpmn/data/data_object_invalid.bpmn b/tests/SpiffWorkflow/bpmn/data/data_object_invalid.bpmn new file mode 100644 index 00000000..1d2d2ed8 --- /dev/null +++ b/tests/SpiffWorkflow/bpmn/data/data_object_invalid.bpmn @@ -0,0 +1,152 @@ + + + + + + Flow_18858hr + + + + + + + + + + Flow_19pyf8s + + + + Flow_1r7v9yo + Flow_1tnu3ej + + + DataObjectReference_0pztwm3 + Property_1uusomz + + + + Flow_18858hr + Flow_0gbxq9s + + DataObjectReference_17fhr1j + + + + Flow_0gbxq9s + Flow_1r7v9yo + + + Flow_1tnu3ej + Flow_19pyf8s + + + DataObjectReference_0cm8dnh + Property_1q5wp77 + + + Flow_0yx8lkz + + + Flow_0yx8lkz + Flow_0rk4i35 + + + + Flow_0rk4i35 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/SpiffWorkflow/bpmn/serializer/dictTest.py b/tests/SpiffWorkflow/bpmn/serializer/dictTest.py deleted file mode 100644 index 3556bee1..00000000 --- a/tests/SpiffWorkflow/bpmn/serializer/dictTest.py +++ /dev/null @@ -1,73 +0,0 @@ -# -*- coding: utf-8 -*- - -from builtins import str -import sys -import unittest -import os -dirname = os.path.dirname(__file__) -sys.path.insert(0, os.path.join(dirname, '..', '..', '..', '..')) - -import uuid -from SpiffWorkflow.bpmn.serializer.dict import BPMNDictionarySerializer -from tests.SpiffWorkflow.serializer.baseTest import SerializerTest -from SpiffWorkflow.workflow import Workflow - - -class BPMNDictionarySerializerTest(SerializerTest): - - def setUp(self): - super(BPMNDictionarySerializerTest, self).setUp() - self.serializer = BPMNDictionarySerializer() - self.return_type = dict - - def _compare_results(self, item1, item2, - exclude_dynamic=False, - exclude_items=None): - exclude_items = exclude_items if exclude_items is not None else [] - if exclude_dynamic: - if 'last_state_change' not in exclude_items: - exclude_items.append('last_state_change') - if 'last_task' not in exclude_items: - exclude_items.append('last_task') - if uuid.UUID not in exclude_items: - exclude_items.append(uuid.UUID) - if type(item1) in exclude_items: - return - - if isinstance(item1, dict): - self.assertIsInstance(item2, dict) - for key, value in list(item1.items()): - self.assertIn(key, item2) - if key in exclude_items: - continue - self._compare_results(value, item2[key], - exclude_dynamic=exclude_dynamic, - exclude_items=exclude_items) - for key in item2: - self.assertIn(key, item1) - - elif isinstance(item1, list): - msg = "item is not a list (is a " + str(type(item2)) + ")" - self.assertIsInstance(item2, list, msg) - msg = "list lengths differ: {} vs {}".format( - len(item1), len(item2)) - self.assertEqual(len(item1), len(item2), msg) - for i, listitem in enumerate(item1): - self._compare_results(listitem, item2[i], - exclude_dynamic=exclude_dynamic, - exclude_items=exclude_items) - - elif isinstance(item1, Workflow): - raise Exception("Item is a Workflow") - - else: - msg = "{}: types differ: {} vs {}".format( - str(item2), type(item1), type(item2)) - self.assertEqual(type(item1), type(item2), msg) - self.assertEqual(item1, item2) - - -def suite(): - return unittest.defaultTestLoader.loadTestsFromTestCase(BPMNDictionarySerializerTest) -if __name__ == '__main__': - unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/tests/SpiffWorkflow/bpmn/serializer/jsonTest.py b/tests/SpiffWorkflow/bpmn/serializer/jsonTest.py deleted file mode 100644 index 89ee0542..00000000 --- a/tests/SpiffWorkflow/bpmn/serializer/jsonTest.py +++ /dev/null @@ -1,38 +0,0 @@ -# -*- coding: utf-8 -*- - -import sys -import unittest -import os -dirname = os.path.dirname(__file__) -sys.path.insert(0, os.path.join(dirname, '..', '..', '..', '..')) - -import json -from SpiffWorkflow.bpmn.serializer.json import BPMNJSONSerializer -from tests.SpiffWorkflow.serializer.dictTest import DictionarySerializerTest - - -class BPMNJSONSerializerTest(DictionarySerializerTest): - - def setUp(self): - super(BPMNJSONSerializerTest, self).setUp() - self.serializer = BPMNJSONSerializer() - self.return_type = str - - def _prepare_result(self, item): - return json.loads(item) - - def _compare_results(self, item1, item2, exclude_dynamic=False, - exclude_items=None): - if exclude_dynamic: - exclude_items = ['__uuid__'] - else: - exclude_items = [] - super(BPMNJSONSerializerTest, self)._compare_results(item1, item2, - exclude_dynamic=exclude_dynamic, - exclude_items=exclude_items) - - -def suite(): - return unittest.defaultTestLoader.loadTestsFromTestCase(BPMNJSONSerializerTest) -if __name__ == '__main__': - unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/tests/SpiffWorkflow/camunda/InvalidBusinessRuleTaskParserTest.py b/tests/SpiffWorkflow/camunda/InvalidBusinessRuleTaskParserTest.py index 3ca9f3d0..757767d6 100644 --- a/tests/SpiffWorkflow/camunda/InvalidBusinessRuleTaskParserTest.py +++ b/tests/SpiffWorkflow/camunda/InvalidBusinessRuleTaskParserTest.py @@ -1,7 +1,7 @@ import os import unittest -from SpiffWorkflow.bpmn.exceptions import WorkflowTaskExecException +from SpiffWorkflow.exceptions import SpiffWorkflowException, WorkflowException from SpiffWorkflow.task import TaskState from SpiffWorkflow.bpmn.workflow import BpmnWorkflow @@ -15,17 +15,23 @@ class BusinessRuleTaskParserTest(BaseTestCase): 'invalid/InvalidDecision.bpmn', 'Process_1', 'invalid_decision.dmn') self.workflow = BpmnWorkflow(self.spec) + def testExceptionPrint(self): + e1 = Exception("test 1") + print (e1) + e = SpiffWorkflowException("test") + print (e) + def testDmnRaisesTaskErrors(self): self.workflow = BpmnWorkflow(self.spec) self.workflow.get_tasks(TaskState.READY)[0].set_data(x=3) try: self.workflow.do_engine_steps() self.assertTrue(False, "An error should have been raised.") - except WorkflowTaskExecException as we: + except WorkflowException as we: self.assertTrue(True, "An error was raised..") - self.assertEquals("InvalidDecisionTaskId", we.sender.name) - self.maxDiff = 1000 - self.assertEquals("Error evaluating expression spam= 1", str(we)) + 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)) def suite(): return unittest.TestLoader().loadTestsFromTestCase(BusinessRuleTaskParserTest) diff --git a/tests/SpiffWorkflow/camunda/data/DMNMultiInstance.bpmn b/tests/SpiffWorkflow/camunda/data/DMNMultiInstance.bpmn index ddf2c44e..d00fd87d 100644 --- a/tests/SpiffWorkflow/camunda/data/DMNMultiInstance.bpmn +++ b/tests/SpiffWorkflow/camunda/data/DMNMultiInstance.bpmn @@ -1,5 +1,5 @@ - + Flow_1b29lxw @@ -46,59 +46,59 @@ of documentation - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - - + - - - - - - - - - - - - + - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/tests/SpiffWorkflow/camunda/data/dmn/test_integer_decision_multi.dmn b/tests/SpiffWorkflow/camunda/data/dmn/test_integer_decision_multi.dmn index 7565b4c0..a24c8400 100644 --- a/tests/SpiffWorkflow/camunda/data/dmn/test_integer_decision_multi.dmn +++ b/tests/SpiffWorkflow/camunda/data/dmn/test_integer_decision_multi.dmn @@ -1,8 +1,8 @@ - + - + item.x diff --git a/tests/SpiffWorkflow/camunda/specs/UserTaskSpecTest.py b/tests/SpiffWorkflow/camunda/specs/UserTaskSpecTest.py index 33f62191..3de8fa2a 100644 --- a/tests/SpiffWorkflow/camunda/specs/UserTaskSpecTest.py +++ b/tests/SpiffWorkflow/camunda/specs/UserTaskSpecTest.py @@ -1,9 +1,7 @@ -import json import unittest -from SpiffWorkflow.camunda.specs.UserTask import FormField, UserTask, Form, \ - EnumFormField -from SpiffWorkflow.specs.base import TaskSpec +from SpiffWorkflow.camunda.specs.UserTask import FormField, UserTask, Form, EnumFormField +from SpiffWorkflow.camunda.serializer.task_spec_converters import UserTaskConverter from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec @@ -13,7 +11,6 @@ class UserTaskSpecTest(unittest.TestCase): def create_instance(self): if 'testtask' in self.wf_spec.task_specs: del self.wf_spec.task_specs['testtask'] - task_spec = TaskSpec(self.wf_spec, 'testtask', description='foo') self.form = Form() return UserTask(self.wf_spec, 'userTask', self.form) @@ -33,43 +30,6 @@ class UserTaskSpecTest(unittest.TestCase): self.assertEqual(self.form, self.user_spec.form) def testSerialize(self): - pass - - def test_text_field(self): - form_field = FormField(form_type="text") - form_field.id = "1234" - self.form.add_field(form_field) - self.assertEqual(form_field, self.user_spec.form.fields[0]) - - def test_enum_field(self): - enum_field = EnumFormField() - enum_field.label = "Which kind of fool are you" - enum_field.add_option('old fool', 'This is old, therefor it is good.') - enum_field.add_option('new fool', - 'This is new, therefor it is better.') - self.form.add_field(enum_field) - self.assertEqual(enum_field, self.user_spec.form.fields[-1]) - - def test_properties(self): - form_field = FormField(form_type="text") - self.assertFalse(form_field.has_property("wilma")) - form_field.add_property("wilma", "flintstone") - self.assertTrue(form_field.has_property("wilma")) - self.assertEquals("flintstone", form_field.get_property("wilma")) - - def test_validations(self): - form_field = FormField(form_type="text") - self.assertFalse(form_field.has_validation("barney")) - form_field.add_validation("barney", "rubble") - self.assertTrue(form_field.has_validation("barney")) - self.assertEquals("rubble", form_field.get_validation("barney")) - - def testIsEngineTask(self): - self.assertFalse(self.user_spec.is_engine_task()) - - def test_convert_to_dict(self): - form = Form() - field1 = FormField(form_type="text") field1.id = "quest" field1.label = "What is your quest?" @@ -89,21 +49,14 @@ class UserTaskSpecTest(unittest.TestCase): field2.add_property("description", "You know what to do.") field2.add_validation("maxlength", "25") - form.key = "formKey" - form.add_field(field1) - form.add_field(field2) + self.form.key = "formKey" + self.form.add_field(field1) + self.form.add_field(field2) - def JsonableHandler(Obj): - if hasattr(Obj, 'jsonable'): - return Obj.jsonable() - else: - raise 'Object of type %s with value of %s is not JSON serializable' % ( - type(Obj), repr(Obj)) - - json_form = json.dumps(form, default=JsonableHandler) - actual = json.loads(json_form) - - expected = { + converter = UserTaskConverter() + dct = converter.to_dict(self.user_spec) + self.assertEqual(dct['name'], 'userTask') + self.assertEqual(dct['form'], { "fields": [ { "default_value": "I seek the grail!", @@ -137,12 +90,39 @@ class UserTaskSpecTest(unittest.TestCase): } ], "key": "formKey", - } + }) - expected_parsed = json.loads(json.dumps(expected)) + def test_text_field(self): + form_field = FormField(form_type="text") + form_field.id = "1234" + self.form.add_field(form_field) + self.assertEqual(form_field, self.user_spec.form.fields[0]) - self.maxDiff = None - self.assertDictEqual(actual, expected_parsed) + def test_enum_field(self): + enum_field = EnumFormField() + enum_field.label = "Which kind of fool are you" + enum_field.add_option('old fool', 'This is old, therefor it is good.') + enum_field.add_option('new fool', + 'This is new, therefor it is better.') + self.form.add_field(enum_field) + self.assertEqual(enum_field, self.user_spec.form.fields[-1]) + + def test_properties(self): + form_field = FormField(form_type="text") + self.assertFalse(form_field.has_property("wilma")) + form_field.add_property("wilma", "flintstone") + self.assertTrue(form_field.has_property("wilma")) + self.assertEquals("flintstone", form_field.get_property("wilma")) + + def test_validations(self): + form_field = FormField(form_type="text") + self.assertFalse(form_field.has_validation("barney")) + form_field.add_validation("barney", "rubble") + self.assertTrue(form_field.has_validation("barney")) + self.assertEquals("rubble", form_field.get_validation("barney")) + + def testIsEngineTask(self): + self.assertFalse(self.user_spec.is_engine_task()) def suite(): diff --git a/tests/SpiffWorkflow/spiff/PrescriptPostscriptTest.py b/tests/SpiffWorkflow/spiff/PrescriptPostscriptTest.py index 52077059..320586a9 100644 --- a/tests/SpiffWorkflow/spiff/PrescriptPostscriptTest.py +++ b/tests/SpiffWorkflow/spiff/PrescriptPostscriptTest.py @@ -1,3 +1,4 @@ +from SpiffWorkflow.exceptions import SpiffWorkflowException from SpiffWorkflow.task import TaskState from .BaseTestCase import BaseTestCase from SpiffWorkflow.bpmn.workflow import BpmnWorkflow @@ -18,7 +19,7 @@ class PrescriptPostsciptTest(BaseTestCase): self.call_activity_test(True) def testDataObject(self): - + spec, subprocesses = self.load_workflow_spec('prescript_postscript_data_object.bpmn', 'Process_1') self.workflow = BpmnWorkflow(spec, subprocesses) # Set a on the workflow and b in the first task. @@ -45,8 +46,21 @@ class PrescriptPostsciptTest(BaseTestCase): ready_tasks[0].complete() self.assertDictEqual({'a': 1, 'b': 2, 'c': 12, 'z': 6}, ready_tasks[0].data) + def test_for_error(self, save_restore=False): + + spec, subprocesses = self.load_workflow_spec('prescript_postscript.bpmn', 'Process_1') + self.workflow = BpmnWorkflow(spec, subprocesses) + if save_restore: + self.save_restore() + ready_tasks = self.workflow.get_tasks(TaskState.READY) + # Calling do-engine steps without setting variables will raise an exception. + with self.assertRaises(SpiffWorkflowException) as se: + self.workflow.do_engine_steps() + ex = se.exception + self.assertIn("Error occurred in the Pre-Script", str(ex)) + def call_activity_test(self, save_restore=False): - + spec, subprocesses = self.load_workflow_spec('prescript_postscript_*.bpmn', 'parent') self.workflow = BpmnWorkflow(spec, subprocesses) if save_restore: diff --git a/tests/SpiffWorkflow/spiff/ServiceTaskTest.py b/tests/SpiffWorkflow/spiff/ServiceTaskTest.py index 1d3035b3..66b2d86a 100644 --- a/tests/SpiffWorkflow/spiff/ServiceTaskTest.py +++ b/tests/SpiffWorkflow/spiff/ServiceTaskTest.py @@ -9,7 +9,6 @@ sys.path.insert(0, os.path.join(dirname, '..', '..', '..')) from SpiffWorkflow.bpmn.PythonScriptEngine import PythonScriptEngine from SpiffWorkflow.bpmn.workflow import BpmnWorkflow -from SpiffWorkflow.bpmn.exceptions import WorkflowTaskExecException from .BaseTestCase import BaseTestCase class ServiceTaskDelegate: diff --git a/tests/SpiffWorkflow/spiff/ServiceTaskVariableTest.py b/tests/SpiffWorkflow/spiff/ServiceTaskVariableTest.py index 12237ae6..834f0c6f 100644 --- a/tests/SpiffWorkflow/spiff/ServiceTaskVariableTest.py +++ b/tests/SpiffWorkflow/spiff/ServiceTaskVariableTest.py @@ -9,7 +9,6 @@ sys.path.insert(0, os.path.join(dirname, '..', '..', '..')) from SpiffWorkflow.bpmn.PythonScriptEngine import PythonScriptEngine from SpiffWorkflow.bpmn.workflow import BpmnWorkflow -from SpiffWorkflow.bpmn.exceptions import WorkflowTaskExecException from .BaseTestCase import BaseTestCase class ServiceTaskDelegate: