From 40c67f000ca119a11df4ce7cd9e7b4f8c9a2f5a0 Mon Sep 17 00:00:00 2001 From: jasquat Date: Wed, 17 May 2023 17:28:51 -0400 Subject: [PATCH] cleaned up process model tests and added support for service tasks w/ burnettk --- .../process_model_test_runner_service.py | 58 ++-------- .../basic_failing_script_task.bpmn | 0 .../process_model.json | 0 .../test_basic_failing_script_task.json | 0 .../basic_call_activity.bpmn | 0 .../basic_call_activity/process_model.json | 0 .../test_basic_call_activity.json | 0 .../basic_manual_task/basic_manual_task.bpmn | 0 .../basic_manual_task/process_model.json | 0 .../test_basic_manual_task.json | 0 .../basic_script_task/basic_script_task.bpmn | 0 .../basic_script_task/process_model.json | 0 .../test_basic_script_task.json | 0 .../basic_service_task.bpmn | 56 ++++++++++ .../basic_service_task/process_model.json | 10 ++ .../test_basic_service_task.json | 10 ++ .../unit/test_process_model_test_runner.py | 100 ++++++++++++++++++ .../test_process_model_test_runner_service.py | 61 ----------- 18 files changed, 186 insertions(+), 109 deletions(-) rename spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/{ => failing_tests}/basic_failing_script_task/basic_failing_script_task.bpmn (100%) rename spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/{ => failing_tests}/basic_failing_script_task/process_model.json (100%) rename spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/{ => failing_tests}/basic_failing_script_task/test_basic_failing_script_task.json (100%) rename spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/{ => passing_tests}/basic_call_activity/basic_call_activity.bpmn (100%) rename spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/{ => passing_tests}/basic_call_activity/process_model.json (100%) rename spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/{ => passing_tests}/basic_call_activity/test_basic_call_activity.json (100%) rename spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/{ => passing_tests}/basic_manual_task/basic_manual_task.bpmn (100%) rename spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/{ => passing_tests}/basic_manual_task/process_model.json (100%) rename spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/{ => passing_tests}/basic_manual_task/test_basic_manual_task.json (100%) rename spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/{ => passing_tests}/basic_script_task/basic_script_task.bpmn (100%) rename spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/{ => passing_tests}/basic_script_task/process_model.json (100%) rename spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/{ => passing_tests}/basic_script_task/test_basic_script_task.json (100%) create mode 100644 spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/passing_tests/basic_service_task/basic_service_task.bpmn create mode 100644 spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/passing_tests/basic_service_task/process_model.json create mode 100644 spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/passing_tests/basic_service_task/test_basic_service_task.json create mode 100644 spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_model_test_runner.py delete mode 100644 spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_model_test_runner_service.py diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_model_test_runner_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_model_test_runner_service.py index 4093e2f6c..7a5569e69 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_model_test_runner_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_model_test_runner_service.py @@ -36,6 +36,10 @@ class MissingBpmnFileForTestCaseError(Exception): pass +class NoTestCasesFoundError(Exception): + pass + + @dataclass class TestCaseResult: passed: bool @@ -95,6 +99,8 @@ class ProcessModelTestRunner: return len(failed_tests) < 1 def run(self) -> None: + if len(self.test_mappings.items()) < 1: + raise NoTestCasesFoundError(f"Could not find any test cases in given directory: {self.process_model_directory_for_test_discovery}") for json_test_case_file, bpmn_file in self.test_mappings.items(): with open(json_test_case_file) as f: json_file_contents = json.loads(f.read()) @@ -189,21 +195,14 @@ class ProcessModelTestRunner: return self.instantiate_executer_callback(bpmn_file) return self._default_instantiate_executer(bpmn_file) - def _get_ready_engine_steps(self, bpmn_process_instance: BpmnWorkflow) -> list[SpiffTask]: - tasks = list([t for t in bpmn_process_instance.get_tasks(TaskState.READY) if not t.task_spec.manual]) - if len(tasks) > 0: - tasks = [tasks[0]] - - return tasks - def _default_get_next_task(self, bpmn_process_instance: BpmnWorkflow) -> Optional[SpiffTask]: - engine_steps = self._get_ready_engine_steps(bpmn_process_instance) - if len(engine_steps) > 0: - return engine_steps[0] + ready_tasks = list([t for t in bpmn_process_instance.get_tasks(TaskState.READY)]) + if len(ready_tasks) > 0: + return ready_tasks[0] return None def _default_execute_task(self, spiff_task: SpiffTask, test_case_task_properties: Optional[dict]) -> None: - if spiff_task.task_spec.manual: + if spiff_task.task_spec.manual or spiff_task.task_spec.__class__.__name__ == 'ServiceTask': if test_case_task_properties and 'data' in test_case_task_properties: spiff_task.update_data(test_case_task_properties['data']) spiff_task.complete() @@ -274,40 +273,3 @@ class ProcessModelTestRunnerService: def run(self) -> None: self.process_model_test_runner.run() - - def _execute_task_callback(self, spiff_task: SpiffTask, _test_case_json: Optional[dict]) -> None: - spiff_task.run() - - def _get_next_task_callback(self, bpmn_process_instance: BpmnWorkflow) -> Optional[SpiffTask]: - engine_steps = self._get_ready_engine_steps(bpmn_process_instance) - if len(engine_steps) > 0: - return engine_steps[0] - return None - - def _get_ready_engine_steps(self, bpmn_process_instance: BpmnWorkflow) -> list[SpiffTask]: - tasks = list([t for t in bpmn_process_instance.get_tasks(TaskState.READY) if not t.task_spec.manual]) - if len(tasks) > 0: - tasks = [tasks[0]] - - return tasks - - def _instantiate_executer_callback(self, bpmn_file: str) -> BpmnWorkflow: - parser = MyCustomParser() - data = None - with open(bpmn_file, "rb") as f_handle: - data = f_handle.read() - etree_xml_parser = etree.XMLParser(resolve_entities=False) - bpmn = etree.fromstring(data, parser=etree_xml_parser) - parser.add_bpmn_xml(bpmn, filename=os.path.basename(bpmn_file)) - sub_parsers = list(parser.process_parsers.values()) - executable_process = None - for sub_parser in sub_parsers: - if sub_parser.process_executable: - executable_process = sub_parser.bpmn_id - if executable_process is None: - raise BpmnFileMissingExecutableProcessError( - f"Executable process cannot be found in {bpmn_file}. Test cannot run." - ) - bpmn_process_spec = parser.get_spec(executable_process) - bpmn_process_instance = BpmnWorkflow(bpmn_process_spec) - return bpmn_process_instance diff --git a/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/basic_failing_script_task/basic_failing_script_task.bpmn b/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/failing_tests/basic_failing_script_task/basic_failing_script_task.bpmn similarity index 100% rename from spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/basic_failing_script_task/basic_failing_script_task.bpmn rename to spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/failing_tests/basic_failing_script_task/basic_failing_script_task.bpmn diff --git a/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/basic_failing_script_task/process_model.json b/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/failing_tests/basic_failing_script_task/process_model.json similarity index 100% rename from spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/basic_failing_script_task/process_model.json rename to spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/failing_tests/basic_failing_script_task/process_model.json diff --git a/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/basic_failing_script_task/test_basic_failing_script_task.json b/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/failing_tests/basic_failing_script_task/test_basic_failing_script_task.json similarity index 100% rename from spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/basic_failing_script_task/test_basic_failing_script_task.json rename to spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/failing_tests/basic_failing_script_task/test_basic_failing_script_task.json diff --git a/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/basic_call_activity/basic_call_activity.bpmn b/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/passing_tests/basic_call_activity/basic_call_activity.bpmn similarity index 100% rename from spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/basic_call_activity/basic_call_activity.bpmn rename to spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/passing_tests/basic_call_activity/basic_call_activity.bpmn diff --git a/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/basic_call_activity/process_model.json b/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/passing_tests/basic_call_activity/process_model.json similarity index 100% rename from spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/basic_call_activity/process_model.json rename to spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/passing_tests/basic_call_activity/process_model.json diff --git a/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/basic_call_activity/test_basic_call_activity.json b/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/passing_tests/basic_call_activity/test_basic_call_activity.json similarity index 100% rename from spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/basic_call_activity/test_basic_call_activity.json rename to spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/passing_tests/basic_call_activity/test_basic_call_activity.json diff --git a/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/basic_manual_task/basic_manual_task.bpmn b/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/passing_tests/basic_manual_task/basic_manual_task.bpmn similarity index 100% rename from spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/basic_manual_task/basic_manual_task.bpmn rename to spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/passing_tests/basic_manual_task/basic_manual_task.bpmn diff --git a/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/basic_manual_task/process_model.json b/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/passing_tests/basic_manual_task/process_model.json similarity index 100% rename from spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/basic_manual_task/process_model.json rename to spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/passing_tests/basic_manual_task/process_model.json diff --git a/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/basic_manual_task/test_basic_manual_task.json b/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/passing_tests/basic_manual_task/test_basic_manual_task.json similarity index 100% rename from spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/basic_manual_task/test_basic_manual_task.json rename to spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/passing_tests/basic_manual_task/test_basic_manual_task.json diff --git a/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/basic_script_task/basic_script_task.bpmn b/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/passing_tests/basic_script_task/basic_script_task.bpmn similarity index 100% rename from spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/basic_script_task/basic_script_task.bpmn rename to spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/passing_tests/basic_script_task/basic_script_task.bpmn diff --git a/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/basic_script_task/process_model.json b/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/passing_tests/basic_script_task/process_model.json similarity index 100% rename from spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/basic_script_task/process_model.json rename to spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/passing_tests/basic_script_task/process_model.json diff --git a/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/basic_script_task/test_basic_script_task.json b/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/passing_tests/basic_script_task/test_basic_script_task.json similarity index 100% rename from spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/basic_script_task/test_basic_script_task.json rename to spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/passing_tests/basic_script_task/test_basic_script_task.json diff --git a/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/passing_tests/basic_service_task/basic_service_task.bpmn b/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/passing_tests/basic_service_task/basic_service_task.bpmn new file mode 100644 index 000000000..8675d5910 --- /dev/null +++ b/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/passing_tests/basic_service_task/basic_service_task.bpmn @@ -0,0 +1,56 @@ + + + + + Flow_19ephzh + + + + Flow_1dsxn78 + + + + + + + + + + + + + + This is the Service Task Unit Test Screen. + + + Flow_0xx2kop + Flow_1dsxn78 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/passing_tests/basic_service_task/process_model.json b/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/passing_tests/basic_service_task/process_model.json new file mode 100644 index 000000000..0946afc6b --- /dev/null +++ b/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/passing_tests/basic_service_task/process_model.json @@ -0,0 +1,10 @@ +{ + "description": "A.1.0.2", + "display_name": "A.1.0.2 - Service Task", + "display_order": 13, + "exception_notification_addresses": [], + "fault_or_suspend_on_exception": "fault", + "files": [], + "primary_file_name": "A.1.0.2.bpmn", + "primary_process_id": "Process_test_a102_A_1_0_2_bd2e724" +} \ No newline at end of file diff --git a/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/passing_tests/basic_service_task/test_basic_service_task.json b/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/passing_tests/basic_service_task/test_basic_service_task.json new file mode 100644 index 000000000..729d81ac2 --- /dev/null +++ b/spiffworkflow-backend/tests/data/bpmn_unit_test_process_models/passing_tests/basic_service_task/test_basic_service_task.json @@ -0,0 +1,10 @@ +{ + "test_case_one": { + "tasks": { + "service_task_one": { + "data": { "the_result": "result_from_service" } + } + }, + "expected_output_json": { "the_result": "result_from_service" } + } +} diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_model_test_runner.py b/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_model_test_runner.py new file mode 100644 index 000000000..a66c9f8a6 --- /dev/null +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_model_test_runner.py @@ -0,0 +1,100 @@ +import os +from typing import Any +from typing import Optional + +import pytest +from flask import current_app +from flask import Flask +from pytest_mock import MockerFixture +from tests.spiffworkflow_backend.helpers.base_test import BaseTest + +from spiffworkflow_backend.models.task import TaskModel # noqa: F401 +from spiffworkflow_backend.services.file_system_service import FileSystemService +from spiffworkflow_backend.services.process_model_test_runner_service import NoTestCasesFoundError, ProcessModelTestRunner + + +class TestProcessModelTestRunner(BaseTest): + def test_can_test_a_simple_process_model( + self, + app: Flask, + with_db_and_bpmn_file_cleanup: None, + with_mocked_root_path: Any, + ) -> None: + process_model_test_runner = self._run_model_tests('basic_script_task') + assert len(process_model_test_runner.test_case_results) == 1 + + def test_will_raise_if_no_tests_found( + self, + app: Flask, + with_db_and_bpmn_file_cleanup: None, + with_mocked_root_path: Any, + ) -> None: + process_model_test_runner = ProcessModelTestRunner( + os.path.join(FileSystemService.root_path(), "DNE") + ) + with pytest.raises(NoTestCasesFoundError): + process_model_test_runner.run() + assert process_model_test_runner.all_test_cases_passed(), process_model_test_runner.test_case_results + + def test_can_test_multiple_process_models_with_all_passing_tests( + self, + app: Flask, + with_db_and_bpmn_file_cleanup: None, + with_mocked_root_path: Any, + ) -> None: + process_model_test_runner = self._run_model_tests() + assert len(process_model_test_runner.test_case_results) > 1 + + def test_can_test_multiple_process_models_with_failing_tests( + self, + app: Flask, + with_db_and_bpmn_file_cleanup: None, + with_mocked_root_path: Any, + ) -> None: + process_model_test_runner = self._run_model_tests(parent_directory='failing_tests') + assert len(process_model_test_runner.test_case_results) == 1 + + def test_can_test_process_model_call_activity( + self, + app: Flask, + with_db_and_bpmn_file_cleanup: None, + with_mocked_root_path: Any, + ) -> None: + process_model_test_runner = self._run_model_tests(bpmn_process_directory_name='basic_call_activity') + assert len(process_model_test_runner.test_case_results) == 1 + + def test_can_test_process_model_with_service_task( + self, + app: Flask, + with_db_and_bpmn_file_cleanup: None, + with_mocked_root_path: Any, + ) -> None: + process_model_test_runner = self._run_model_tests(bpmn_process_directory_name='basic_service_task') + assert len(process_model_test_runner.test_case_results) == 1 + + def _run_model_tests(self, bpmn_process_directory_name: Optional[str] = None, parent_directory: str = 'passing_tests') -> ProcessModelTestRunner: + base_process_model_dir_path_segments = [FileSystemService.root_path(), parent_directory] + path_segments = base_process_model_dir_path_segments + if bpmn_process_directory_name: + path_segments = path_segments + [bpmn_process_directory_name] + process_model_test_runner = ProcessModelTestRunner( + process_model_directory_path=os.path.join(*base_process_model_dir_path_segments), + process_model_directory_for_test_discovery=os.path.join(*path_segments) + ) + process_model_test_runner.run() + + all_tests_expected_to_pass = parent_directory == 'passing_tests' + assert process_model_test_runner.all_test_cases_passed() is all_tests_expected_to_pass, process_model_test_runner.test_case_results + return process_model_test_runner + + @pytest.fixture() + def with_mocked_root_path(self, mocker: MockerFixture) -> None: + path = os.path.join( + current_app.instance_path, + "..", + "..", + "tests", + "data", + "bpmn_unit_test_process_models", + ) + mocker.patch.object(FileSystemService, attribute="root_path", return_value=path) diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_model_test_runner_service.py b/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_model_test_runner_service.py deleted file mode 100644 index 89ed9ec77..000000000 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_model_test_runner_service.py +++ /dev/null @@ -1,61 +0,0 @@ -import os -from typing import Any - -import pytest -from flask import current_app -from flask import Flask -from pytest_mock import MockerFixture -from tests.spiffworkflow_backend.helpers.base_test import BaseTest - -from spiffworkflow_backend.models.task import TaskModel # noqa: F401 -from spiffworkflow_backend.services.file_system_service import FileSystemService -from spiffworkflow_backend.services.process_model_test_runner_service import ProcessModelTestRunner, ProcessModelTestRunnerService - - -class TestProcessModelTestRunnerService(BaseTest): - def test_can_test_a_simple_process_model( - self, - app: Flask, - with_db_and_bpmn_file_cleanup: None, - with_mocked_root_path: Any, - ) -> None: - test_runner_service = ProcessModelTestRunnerService( - os.path.join(FileSystemService.root_path(), "basic_script_task") - ) - test_runner_service.run() - assert test_runner_service.process_model_test_runner.all_test_cases_passed(), test_runner_service.process_model_test_runner.test_case_results - - def test_can_test_multiple_process_models( - self, - app: Flask, - with_db_and_bpmn_file_cleanup: None, - with_mocked_root_path: Any, - ) -> None: - test_runner_service = ProcessModelTestRunnerService(FileSystemService.root_path()) - test_runner_service.run() - assert test_runner_service.process_model_test_runner.all_test_cases_passed() is False - - def test_can_test_process_model_call_activity( - self, - app: Flask, - with_db_and_bpmn_file_cleanup: None, - with_mocked_root_path: Any, - ) -> None: - test_runner_service = ProcessModelTestRunner( - process_model_directory_path=FileSystemService.root_path(), - process_model_directory_for_test_discovery=os.path.join(FileSystemService.root_path(), "basic_call_activity") - ) - test_runner_service.run() - assert test_runner_service.all_test_cases_passed() is True, test_runner_service.test_case_results - - @pytest.fixture() - def with_mocked_root_path(self, mocker: MockerFixture) -> None: - path = os.path.join( - current_app.instance_path, - "..", - "..", - "tests", - "data", - "bpmn_unit_test_process_models", - ) - mocker.patch.object(FileSystemService, attribute="root_path", return_value=path)