diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py index c59eba4b..53ceef2c 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py @@ -1,19 +1,13 @@ """Error_handling_service.""" -import json from typing import Union from flask import current_app from flask import g -from flask.wrappers import Response from spiffworkflow_backend.exceptions.api_error import ApiError from spiffworkflow_backend.models.db import db from spiffworkflow_backend.models.message_instance import MessageInstanceModel -from spiffworkflow_backend.models.message_triggerable_process_model import ( - MessageTriggerableProcessModel, -) from spiffworkflow_backend.models.process_instance import ProcessInstanceModel -from spiffworkflow_backend.models.process_instance import ProcessInstanceModelSchema from spiffworkflow_backend.models.process_instance import ProcessInstanceStatus from spiffworkflow_backend.models.process_model import ProcessModelInfo from spiffworkflow_backend.services.message_service import MessageService @@ -72,18 +66,19 @@ class ErrorHandlingService: @staticmethod def handle_system_notification( - error: Union[ApiError, Exception], - process_model: ProcessModelInfo, - _processor: ProcessInstanceProcessor - ) -> Response: - """Send a BPMN Message - which may kick off a waiting process. """ + error: Union[ApiError, Exception], + process_model: ProcessModelInfo, + _processor: ProcessInstanceProcessor, + ) -> None: + """Send a BPMN Message - which may kick off a waiting process.""" message_text = ( f"There was an exception running process {process_model.id}.\nOriginal" f" Error:\n{error.__repr__()}" ) - message_payload = {"message_text": message_text, - "recipients": process_model.exception_notification_addresses - } + message_payload = { + "message_text": message_text, + "recipients": process_model.exception_notification_addresses, + } user_id = None if "user" in g: user_id = g.user.id diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_error_handling.py b/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_error_handling.py index 424aa3a1..9d481788 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_error_handling.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_error_handling.py @@ -1,44 +1,52 @@ import pytest from flask import Flask from flask.testing import FlaskClient +from tests.spiffworkflow_backend.helpers.base_test import BaseTest +from tests.spiffworkflow_backend.helpers.test_data import load_test_spec -from conftest import with_super_admin_user from spiffworkflow_backend import db from spiffworkflow_backend.exceptions.api_error import ApiError from spiffworkflow_backend.models.message_instance import MessageInstanceModel +from spiffworkflow_backend.models.process_instance import ProcessInstanceModel from spiffworkflow_backend.models.process_instance import ProcessInstanceStatus from spiffworkflow_backend.models.process_model import ProcessModelInfo from spiffworkflow_backend.models.user import UserModel from spiffworkflow_backend.services.error_handling_service import ErrorHandlingService -from spiffworkflow_backend.services.process_instance_processor import ProcessInstanceProcessor -from spiffworkflow_backend.services.process_instance_service import ProcessInstanceService +from spiffworkflow_backend.services.process_instance_processor import ( + ProcessInstanceProcessor, +) +from spiffworkflow_backend.services.process_instance_service import ( + ProcessInstanceService, +) from spiffworkflow_backend.services.process_model_service import ProcessModelService -from tests.spiffworkflow_backend.helpers.base_test import BaseTest -from tests.spiffworkflow_backend.helpers.test_data import load_test_spec class TestErrorHandlingService(BaseTest): - """Error Handling does some crazy stuff man, like even firing off - messages in case a BPMN Task is waiting for that message. """ + """Error Handling does some crazy stuff man. - def run_process_model_and_handle_error(self, process_model: ProcessModelInfo, user: UserModel) -> Exception: + Like it can fire off BPMN messages in case a BPMN Task is waiting for that message. + """ + + def run_process_model_and_handle_error( + self, process_model: ProcessModelInfo, user: UserModel + ) -> ProcessInstanceModel: process_instance = ProcessInstanceService.create_process_instance_from_process_model_identifier( - process_model.id, user) - pip = ProcessInstanceProcessor(process_instance) + process_model.id, user + ) + pip = ProcessInstanceProcessor(process_instance) with pytest.raises(ApiError) as e: pip.do_engine_steps(save=True) - ErrorHandlingService().handle_error(pip, e) + ErrorHandlingService().handle_error(pip, e.value) return process_instance - def test_handle_error_suspends_or_faults_process( - self, - app: Flask, - client: FlaskClient, - with_db_and_bpmn_file_cleanup: None, - with_super_admin_user: UserModel, + self, + app: Flask, + client: FlaskClient, + with_db_and_bpmn_file_cleanup: None, + with_super_admin_user: UserModel, ) -> None: - """ Process Model in DB marked as suspended when error occurs""" + """Process Model in DB marked as suspended when error occurs.""" process_model = load_test_spec( "test_group/error_suspend", process_model_source_directory="error", @@ -46,42 +54,51 @@ class TestErrorHandlingService(BaseTest): ) # Process instance should be marked as errored by default. - process_instance = self.run_process_model_and_handle_error(process_model, with_super_admin_user) - assert(ProcessInstanceStatus.error.value == process_instance.status) + process_instance = self.run_process_model_and_handle_error( + process_model, with_super_admin_user + ) + assert ProcessInstanceStatus.error.value == process_instance.status # If process model should be suspended on error, then that is what should happen. process_model.fault_or_suspend_on_exception = "suspend" ProcessModelService.save_process_model(process_model) - process_instance = self.run_process_model_and_handle_error(process_model, with_super_admin_user) - assert(ProcessInstanceStatus.suspended.value == process_instance.status) + process_instance = self.run_process_model_and_handle_error( + process_model, with_super_admin_user + ) + assert ProcessInstanceStatus.suspended.value == process_instance.status def test_error_sends_bpmn_message( - self, - app: Flask, - client: FlaskClient, - with_db_and_bpmn_file_cleanup: None, - with_super_admin_user: UserModel): - """ Process Model in DB marked as suspended when error occurs""" + self, + app: Flask, + client: FlaskClient, + with_db_and_bpmn_file_cleanup: None, + with_super_admin_user: UserModel, + ) -> None: + """Real BPMN Messages should get generated and processes should fire off and complete.""" process_model = load_test_spec( "test_group/error_send_message_bpmn", process_model_source_directory="error", bpmn_file_name="error.bpmn", # Slightly misnamed, it sends and receives ) """ Process Model that will listen for errors sent.""" - process_model_error_handler = load_test_spec( + load_test_spec( "test_group/admin_tools/error_handler", process_model_source_directory="error", bpmn_file_name="error_handler.bpmn", # Slightly misnamed, it sends and receives ) - process_model.exception_notification_addresses=["dan@ILoveToReadErrorsInMyEmails.com"] + process_model.exception_notification_addresses = [ + "dan@ILoveToReadErrorsInMyEmails.com" + ] ProcessModelService.save_process_model(process_model) # kick off the process and assure it got marked as an error. - process_instance = self.run_process_model_and_handle_error(process_model, with_super_admin_user) - assert(ProcessInstanceStatus.error.value == process_instance.status) + process_instance = self.run_process_model_and_handle_error( + process_model, with_super_admin_user + ) + assert ProcessInstanceStatus.error.value == process_instance.status # Both send and receive messages should be generated, matched # and considered complete. messages = db.session.query(MessageInstanceModel).all() - assert(2 == len(messages)) - assert("completed", messages[0].status) - assert("completed", messages[1].status) \ No newline at end of file + assert 2 == len(messages) + assert "completed" == messages[0].status + assert "completed" == messages[1].status