do not allow sending messages to terminated and suspended process instances w/ burnettk

This commit is contained in:
jasquat 2023-01-06 16:21:29 -05:00
parent acef4bae07
commit 0bf232d92b
3 changed files with 131 additions and 11 deletions

View File

@ -1820,7 +1820,7 @@ paths:
post: post:
tags: tags:
- Messages - Messages
operationId: spiffworkflow_backend.routes.messages_controller.message_start operationId: spiffworkflow_backend.routes.messages_controller.message_send
summary: Instantiate and run a given process model with a message start event matching given identifier summary: Instantiate and run a given process model with a message start event matching given identifier
requestBody: requestBody:
content: content:

View File

@ -19,6 +19,7 @@ from spiffworkflow_backend.models.message_triggerable_process_model import (
) )
from spiffworkflow_backend.models.process_instance import ProcessInstanceModel from spiffworkflow_backend.models.process_instance import ProcessInstanceModel
from spiffworkflow_backend.models.process_instance import ProcessInstanceModelSchema from spiffworkflow_backend.models.process_instance import ProcessInstanceModelSchema
from spiffworkflow_backend.models.process_instance import ProcessInstanceStatus
from spiffworkflow_backend.routes.process_api_blueprint import ( from spiffworkflow_backend.routes.process_api_blueprint import (
_find_process_instance_by_id_or_raise, _find_process_instance_by_id_or_raise,
) )
@ -90,7 +91,7 @@ def message_instance_list(
# payload: dict, # payload: dict,
# process_instance_id: Optional[int], # process_instance_id: Optional[int],
# } # }
def message_start( def message_send(
message_identifier: str, message_identifier: str,
body: Dict[str, Any], body: Dict[str, Any],
) -> flask.wrappers.Response: ) -> flask.wrappers.Response:
@ -121,6 +122,26 @@ def message_start(
body["process_instance_id"] body["process_instance_id"]
) )
if process_instance.status == ProcessInstanceStatus.suspended.value:
raise ApiError(
error_code="process_instance_is_suspended",
message=(
f"Process Instance '{process_instance.id}' is suspended and cannot"
" accept messages.'"
),
status_code=400,
)
if process_instance.status == ProcessInstanceStatus.terminated.value:
raise ApiError(
error_code="process_instance_is_terminated",
message=(
f"Process Instance '{process_instance.id}' is terminated and cannot"
" accept messages.'"
),
status_code=400,
)
message_instance = MessageInstanceModel.query.filter_by( message_instance = MessageInstanceModel.query.filter_by(
process_instance_id=process_instance.id, process_instance_id=process_instance.id,
message_model_id=message_model.id, message_model_id=message_model.id,

View File

@ -1296,16 +1296,16 @@ class TestProcessApi(BaseTest):
xml_file_contents = f_open.read() xml_file_contents = f_open.read()
assert show_response.json["bpmn_xml_file_contents"] == xml_file_contents assert show_response.json["bpmn_xml_file_contents"] == xml_file_contents
def test_message_start_when_starting_process_instance( def test_message_send_when_starting_process_instance(
self, self,
app: Flask, app: Flask,
client: FlaskClient, client: FlaskClient,
with_db_and_bpmn_file_cleanup: None, with_db_and_bpmn_file_cleanup: None,
with_super_admin_user: UserModel, with_super_admin_user: UserModel,
) -> None: ) -> None:
"""Test_message_start_when_starting_process_instance.""" """Test_message_send_when_starting_process_instance."""
# ensure process model is loaded # ensure process model is loaded
process_group_id = "test_message_start" process_group_id = "test_message_send"
process_model_id = "message_receiver" process_model_id = "message_receiver"
bpmn_file_name = "message_receiver.bpmn" bpmn_file_name = "message_receiver.bpmn"
bpmn_file_location = "message_send_one_conversation" bpmn_file_location = "message_send_one_conversation"
@ -1345,15 +1345,15 @@ class TestProcessApi(BaseTest):
assert process_instance_data assert process_instance_data
assert process_instance_data["the_payload"] == payload assert process_instance_data["the_payload"] == payload
def test_message_start_when_providing_message_to_running_process_instance( def test_message_send_when_providing_message_to_running_process_instance(
self, self,
app: Flask, app: Flask,
client: FlaskClient, client: FlaskClient,
with_db_and_bpmn_file_cleanup: None, with_db_and_bpmn_file_cleanup: None,
with_super_admin_user: UserModel, with_super_admin_user: UserModel,
) -> None: ) -> None:
"""Test_message_start_when_providing_message_to_running_process_instance.""" """Test_message_send_when_providing_message_to_running_process_instance."""
process_group_id = "test_message_start" process_group_id = "test_message_send"
process_model_id = "message_sender" process_model_id = "message_sender"
bpmn_file_name = "message_sender.bpmn" bpmn_file_name = "message_sender.bpmn"
bpmn_file_location = "message_send_one_conversation" bpmn_file_location = "message_send_one_conversation"
@ -1412,6 +1412,105 @@ class TestProcessApi(BaseTest):
assert process_instance_data assert process_instance_data
assert process_instance_data["the_payload"] == payload assert process_instance_data["the_payload"] == payload
def test_message_send_errors_when_providing_message_to_suspended_process_instance(
self,
app: Flask,
client: FlaskClient,
with_db_and_bpmn_file_cleanup: None,
with_super_admin_user: UserModel,
) -> None:
"""Test_message_send_when_providing_message_to_running_process_instance."""
process_group_id = "test_message_send"
process_model_id = "message_sender"
bpmn_file_name = "message_sender.bpmn"
bpmn_file_location = "message_send_one_conversation"
process_model_identifier = self.create_group_and_model_with_bpmn(
client,
with_super_admin_user,
process_group_id=process_group_id,
process_model_id=process_model_id,
bpmn_file_name=bpmn_file_name,
bpmn_file_location=bpmn_file_location,
)
message_model_identifier = "message_response"
payload = {
"the_payload": {
"topica": "the_payload.topica_string",
"topicb": "the_payload.topicb_string",
"andThis": "another_item_non_key",
}
}
response = self.create_process_instance_from_process_model_id_with_api(
client,
process_model_identifier,
self.logged_in_headers(with_super_admin_user),
)
assert response.json is not None
process_instance_id = response.json["id"]
response = client.post(
f"/v1.0/process-instances/{self.modify_process_identifier_for_path_param(process_model_identifier)}/{process_instance_id}/run",
headers=self.logged_in_headers(with_super_admin_user),
)
assert response.status_code == 200
assert response.json is not None
process_instance = ProcessInstanceModel.query.filter_by(
id=process_instance_id
).first()
processor = ProcessInstanceProcessor(process_instance)
processor.suspend()
response = client.post(
f"/v1.0/messages/{message_model_identifier}",
content_type="application/json",
headers=self.logged_in_headers(with_super_admin_user),
data=json.dumps(
{"payload": payload, "process_instance_id": process_instance_id}
),
)
assert response.status_code == 400
assert response.json
assert response.json["error_code"] == "process_instance_is_suspended"
processor.resume()
response = client.post(
f"/v1.0/messages/{message_model_identifier}",
content_type="application/json",
headers=self.logged_in_headers(with_super_admin_user),
data=json.dumps(
{"payload": payload, "process_instance_id": process_instance_id}
),
)
assert response.status_code == 200
json_data = response.json
assert json_data
assert json_data["status"] == "complete"
process_instance_id = json_data["id"]
process_instance = ProcessInstanceModel.query.filter_by(
id=process_instance_id
).first()
assert process_instance
processor = ProcessInstanceProcessor(process_instance)
process_instance_data = processor.get_data()
assert process_instance_data
assert process_instance_data["the_payload"] == payload
processor.terminate()
response = client.post(
f"/v1.0/messages/{message_model_identifier}",
content_type="application/json",
headers=self.logged_in_headers(with_super_admin_user),
data=json.dumps(
{"payload": payload, "process_instance_id": process_instance_id}
),
)
assert response.status_code == 400
assert response.json
assert response.json["error_code"] == "process_instance_is_terminated"
def test_process_instance_can_be_terminated( def test_process_instance_can_be_terminated(
self, self,
app: Flask, app: Flask,
@ -1419,9 +1518,9 @@ class TestProcessApi(BaseTest):
with_db_and_bpmn_file_cleanup: None, with_db_and_bpmn_file_cleanup: None,
with_super_admin_user: UserModel, with_super_admin_user: UserModel,
) -> None: ) -> None:
"""Test_message_start_when_providing_message_to_running_process_instance.""" """Test_message_send_when_providing_message_to_running_process_instance."""
# this task will wait on a catch event # this task will wait on a catch event
process_group_id = "test_message_start" process_group_id = "test_message_send"
process_model_id = "message_sender" process_model_id = "message_sender"
bpmn_file_name = "message_sender.bpmn" bpmn_file_name = "message_sender.bpmn"
bpmn_file_location = "message_send_one_conversation" bpmn_file_location = "message_send_one_conversation"
@ -2188,7 +2287,7 @@ class TestProcessApi(BaseTest):
with_super_admin_user: UserModel, with_super_admin_user: UserModel,
) -> None: ) -> None:
"""Test_can_get_message_instances_by_process_instance_id.""" """Test_can_get_message_instances_by_process_instance_id."""
process_group_id = "test_message_start" process_group_id = "test_message_send"
process_model_id = "message_receiver" process_model_id = "message_receiver"
bpmn_file_name = "message_receiver.bpmn" bpmn_file_name = "message_receiver.bpmn"
bpmn_file_location = "message_send_one_conversation" bpmn_file_location = "message_send_one_conversation"