run_pyl
This commit is contained in:
parent
5171e53240
commit
7b16625cff
|
@ -5,13 +5,9 @@ import shutil
|
||||||
import pytest
|
import pytest
|
||||||
from flask.app import Flask
|
from flask.app import Flask
|
||||||
from flask.testing import FlaskClient
|
from flask.testing import FlaskClient
|
||||||
|
|
||||||
from spiffworkflow_backend.models import message_correlation_message_instance
|
|
||||||
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
|
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
|
||||||
|
|
||||||
from spiffworkflow_backend.models.db import db
|
from spiffworkflow_backend.models.db import db
|
||||||
from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel
|
|
||||||
from spiffworkflow_backend.models.human_task_user import HumanTaskUserModel
|
|
||||||
from spiffworkflow_backend.models.process_instance import ProcessInstanceModel
|
from spiffworkflow_backend.models.process_instance import ProcessInstanceModel
|
||||||
from spiffworkflow_backend.models.user import UserModel
|
from spiffworkflow_backend.models.user import UserModel
|
||||||
from spiffworkflow_backend.services.process_instance_processor import (
|
from spiffworkflow_backend.services.process_instance_processor import (
|
||||||
|
@ -48,14 +44,12 @@ def app() -> Flask:
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def with_db_and_bpmn_file_cleanup() -> None:
|
def with_db_and_bpmn_file_cleanup() -> None:
|
||||||
|
"""Do it cleanly!"""
|
||||||
meta = db.metadata
|
meta = db.metadata
|
||||||
for table in reversed(meta.sorted_tables):
|
for table in reversed(meta.sorted_tables):
|
||||||
print
|
|
||||||
'Clear table %s' % table
|
|
||||||
db.session.execute(table.delete())
|
db.session.execute(table.delete())
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
yield
|
yield
|
||||||
finally:
|
finally:
|
||||||
|
|
|
@ -94,7 +94,6 @@ def create_app() -> flask.app.Flask:
|
||||||
app.config["CONNEXION_APP"] = connexion_app
|
app.config["CONNEXION_APP"] = connexion_app
|
||||||
app.config["SESSION_TYPE"] = "filesystem"
|
app.config["SESSION_TYPE"] = "filesystem"
|
||||||
|
|
||||||
|
|
||||||
setup_config(app)
|
setup_config(app)
|
||||||
db.init_app(app)
|
db.init_app(app)
|
||||||
migrate.init_app(app, db)
|
migrate.init_app(app, db)
|
||||||
|
|
|
@ -2,9 +2,7 @@
|
||||||
import re
|
import re
|
||||||
from os import environ
|
from os import environ
|
||||||
|
|
||||||
FLASK_SESSION_SECRET_KEY = environ.get(
|
FLASK_SESSION_SECRET_KEY = environ.get("FLASK_SESSION_SECRET_KEY")
|
||||||
"FLASK_SESSION_SECRET_KEY"
|
|
||||||
)
|
|
||||||
|
|
||||||
SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR = environ.get(
|
SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR = environ.get(
|
||||||
"SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR"
|
"SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR"
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
"""Message_correlation."""
|
"""Message_correlation."""
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
|
|
||||||
from sqlalchemy import ForeignKey
|
from sqlalchemy import ForeignKey
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
|
@ -40,4 +39,3 @@ class MessageCorrelationModel(SpiffworkflowBaseDBModel):
|
||||||
created_at_in_seconds: int = db.Column(db.Integer)
|
created_at_in_seconds: int = db.Column(db.Integer)
|
||||||
|
|
||||||
message_correlation_property = relationship("MessageCorrelationPropertyModel")
|
message_correlation_property = relationship("MessageCorrelationPropertyModel")
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
"""Message_correlation_message_instance."""
|
"""Message_correlation_message_instance."""
|
||||||
|
|
||||||
from sqlalchemy import ForeignKey
|
from sqlalchemy import ForeignKey
|
||||||
from spiffworkflow_backend.models.db import db
|
|
||||||
from spiffworkflow_backend.models.message_correlation import MessageCorrelationModel
|
|
||||||
|
|
||||||
message_correlation_message_instance_table \
|
from spiffworkflow_backend.models.db import db
|
||||||
= db.Table('message_correlation_message_instance',
|
|
||||||
db.Column('message_instance_id',
|
message_correlation_message_instance_table = db.Table(
|
||||||
ForeignKey('message_instance.id'), primary_key=True),
|
"message_correlation_message_instance",
|
||||||
db.Column('message_correlation_id',
|
db.Column(
|
||||||
ForeignKey('message_correlation.id'),primary_key=True),
|
"message_instance_id", ForeignKey("message_instance.id"), primary_key=True
|
||||||
)
|
),
|
||||||
|
db.Column(
|
||||||
|
"message_correlation_id", ForeignKey("message_correlation.id"), primary_key=True
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
|
@ -23,5 +23,4 @@ class MessageCorrelationPropertyModel(SpiffworkflowBaseDBModel):
|
||||||
message_model_id = db.Column(ForeignKey(MessageModel.id), nullable=False)
|
message_model_id = db.Column(ForeignKey(MessageModel.id), nullable=False)
|
||||||
updated_at_in_seconds: int = db.Column(db.Integer)
|
updated_at_in_seconds: int = db.Column(db.Integer)
|
||||||
created_at_in_seconds: int = db.Column(db.Integer)
|
created_at_in_seconds: int = db.Column(db.Integer)
|
||||||
message_model = db.relationship("MessageModel",
|
message_model = db.relationship("MessageModel", backref="correlation_properties")
|
||||||
backref="correlation_properties")
|
|
||||||
|
|
|
@ -1,24 +1,23 @@
|
||||||
"""Message_instance."""
|
"""Message_instance."""
|
||||||
import enum
|
import enum
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Any, Self
|
from typing import Any
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
|
|
||||||
from sqlalchemy import ForeignKey
|
from sqlalchemy import ForeignKey
|
||||||
from sqlalchemy.event import listens_for
|
from sqlalchemy.event import listens_for
|
||||||
from sqlalchemy.orm import relationship
|
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from sqlalchemy.orm import validates
|
from sqlalchemy.orm import validates
|
||||||
|
|
||||||
from spiffworkflow_backend.models.db import db
|
from spiffworkflow_backend.models.db import db
|
||||||
from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel
|
from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel
|
||||||
from spiffworkflow_backend.models.message_correlation_message_instance import message_correlation_message_instance_table
|
from spiffworkflow_backend.models.message_correlation_message_instance import (
|
||||||
|
message_correlation_message_instance_table,
|
||||||
|
)
|
||||||
from spiffworkflow_backend.models.message_model import MessageModel
|
from spiffworkflow_backend.models.message_model import MessageModel
|
||||||
from spiffworkflow_backend.models.process_instance import ProcessInstanceModel
|
from spiffworkflow_backend.models.process_instance import ProcessInstanceModel
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MessageTypes(enum.Enum):
|
class MessageTypes(enum.Enum):
|
||||||
"""MessageTypes."""
|
"""MessageTypes."""
|
||||||
|
|
||||||
|
@ -35,7 +34,6 @@ class MessageStatuses(enum.Enum):
|
||||||
failed = "failed"
|
failed = "failed"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MessageInstanceModel(SpiffworkflowBaseDBModel):
|
class MessageInstanceModel(SpiffworkflowBaseDBModel):
|
||||||
"""Messages from a process instance that are ready to send to a receiving task."""
|
"""Messages from a process instance that are ready to send to a receiving task."""
|
||||||
|
@ -46,10 +44,12 @@ class MessageInstanceModel(SpiffworkflowBaseDBModel):
|
||||||
process_instance_id: int = db.Column(ForeignKey(ProcessInstanceModel.id), nullable=False) # type: ignore
|
process_instance_id: int = db.Column(ForeignKey(ProcessInstanceModel.id), nullable=False) # type: ignore
|
||||||
message_model_id: int = db.Column(ForeignKey(MessageModel.id), nullable=False)
|
message_model_id: int = db.Column(ForeignKey(MessageModel.id), nullable=False)
|
||||||
message_model = db.relationship("MessageModel")
|
message_model = db.relationship("MessageModel")
|
||||||
message_correlations = db.relationship("MessageCorrelationModel",
|
message_correlations = db.relationship(
|
||||||
secondary=message_correlation_message_instance_table,
|
"MessageCorrelationModel",
|
||||||
backref="message_instances",
|
secondary=message_correlation_message_instance_table,
|
||||||
cascade="all,delete")
|
backref="message_instances",
|
||||||
|
cascade="all,delete",
|
||||||
|
)
|
||||||
|
|
||||||
message_type: str = db.Column(db.String(20), nullable=False)
|
message_type: str = db.Column(db.String(20), nullable=False)
|
||||||
payload: str = db.Column(db.JSON)
|
payload: str = db.Column(db.JSON)
|
||||||
|
@ -68,20 +68,21 @@ class MessageInstanceModel(SpiffworkflowBaseDBModel):
|
||||||
"""Validate_status."""
|
"""Validate_status."""
|
||||||
return self.validate_enum_field(key, value, MessageStatuses)
|
return self.validate_enum_field(key, value, MessageStatuses)
|
||||||
|
|
||||||
def correlation_dictionary(self):
|
def correlation_dictionary(self) -> dict:
|
||||||
correlation_dict = {}
|
correlation_dict = {}
|
||||||
for c in self.message_correlations:
|
for c in self.message_correlations:
|
||||||
correlation_dict[c.name]=c.value
|
correlation_dict[c.name] = c.value
|
||||||
return correlation_dict
|
return correlation_dict
|
||||||
|
|
||||||
def correlates(self, other_message_instance: Self) -> bool:
|
def correlates(self, other_message_instance: Any) -> bool:
|
||||||
if other_message_instance.message_model_id != self.message_model_id:
|
if other_message_instance.message_model_id != self.message_model_id:
|
||||||
return False
|
return False
|
||||||
return self.correlates_with_dictionary(other_message_instance.correlation_dictionary())
|
return self.correlates_with_dictionary(
|
||||||
|
other_message_instance.correlation_dictionary()
|
||||||
|
)
|
||||||
|
|
||||||
def correlates_with_dictionary(self, dict: dict) -> bool:
|
def correlates_with_dictionary(self, dict: dict) -> bool:
|
||||||
"""Returns true if the given dictionary matches the correlation
|
"""Returns true if the given dictionary matches the correlation names and values connected to this instance."""
|
||||||
names and values connected to this message instance"""
|
|
||||||
for c in self.message_correlations:
|
for c in self.message_correlations:
|
||||||
# Fixme: Maybe we should look at typing the correlations and not forcing them to strings?
|
# Fixme: Maybe we should look at typing the correlations and not forcing them to strings?
|
||||||
if c.name in dict and str(dict[c.name]) == c.value:
|
if c.name in dict and str(dict[c.name]) == c.value:
|
||||||
|
@ -90,9 +91,6 @@ class MessageInstanceModel(SpiffworkflowBaseDBModel):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
corrs = {}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# This runs for ALL db flushes for ANY model, not just this one even if it's in the MessageInstanceModel class
|
# This runs for ALL db flushes for ANY model, not just this one even if it's in the MessageInstanceModel class
|
||||||
# so this may not be worth it or there may be a better way to do it
|
# so this may not be worth it or there may be a better way to do it
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
"""Message_model."""
|
"""Message_model."""
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from spiffworkflow_backend.models.db import db
|
from spiffworkflow_backend.models.db import db
|
||||||
from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel
|
from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel
|
||||||
|
|
||||||
|
@ -13,8 +15,8 @@ class MessageModel(SpiffworkflowBaseDBModel):
|
||||||
name = db.Column(db.String(50), unique=True, index=True)
|
name = db.Column(db.String(50), unique=True, index=True)
|
||||||
# correlation_properties is a backref and defined in the MessageCorrelationProperties class.
|
# correlation_properties is a backref and defined in the MessageCorrelationProperties class.
|
||||||
|
|
||||||
def get_correlation_property(self, identifier):
|
def get_correlation_property(self, identifier: str) -> Any | None:
|
||||||
for corr_prop in self.correlation_properties:
|
for corr_prop in self.correlation_properties:
|
||||||
if corr_prop.identifier == identifier:
|
if corr_prop.identifier == identifier:
|
||||||
return corr_prop;
|
return corr_prop
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -11,8 +11,6 @@ from flask import make_response
|
||||||
from flask.wrappers import Response
|
from flask.wrappers import Response
|
||||||
|
|
||||||
from spiffworkflow_backend.exceptions.api_error import ApiError
|
from spiffworkflow_backend.exceptions.api_error import ApiError
|
||||||
from spiffworkflow_backend.models.message_correlation import MessageCorrelationModel
|
|
||||||
from spiffworkflow_backend.models.message_correlation_property import MessageCorrelationPropertyModel
|
|
||||||
from spiffworkflow_backend.models.message_instance import MessageInstanceModel
|
from spiffworkflow_backend.models.message_instance import MessageInstanceModel
|
||||||
from spiffworkflow_backend.models.message_model import MessageModel
|
from spiffworkflow_backend.models.message_model import MessageModel
|
||||||
from spiffworkflow_backend.models.message_triggerable_process_model import (
|
from spiffworkflow_backend.models.message_triggerable_process_model import (
|
||||||
|
@ -21,9 +19,6 @@ 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.models.process_instance import ProcessInstanceStatus
|
||||||
from spiffworkflow_backend.routes.process_api_blueprint import (
|
|
||||||
_find_process_instance_by_id_or_raise,
|
|
||||||
)
|
|
||||||
from spiffworkflow_backend.services.message_service import MessageService
|
from spiffworkflow_backend.services.message_service import MessageService
|
||||||
|
|
||||||
|
|
||||||
|
@ -91,7 +86,10 @@ def message_send(
|
||||||
raise (
|
raise (
|
||||||
ApiError(
|
ApiError(
|
||||||
error_code="missing_payload",
|
error_code="missing_payload",
|
||||||
message="Please include a 'payload' in the JSON body that contains the message contents.",
|
message=(
|
||||||
|
"Please include a 'payload' in the JSON body that contains the"
|
||||||
|
" message contents."
|
||||||
|
),
|
||||||
status_code=400,
|
status_code=400,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -99,7 +97,9 @@ def message_send(
|
||||||
process_instance = None
|
process_instance = None
|
||||||
|
|
||||||
# Is there a running instance that is waiting for this message?
|
# Is there a running instance that is waiting for this message?
|
||||||
message_instances = MessageInstanceModel.query.filter_by(message_model_id=message_model.id).all()
|
message_instances = MessageInstanceModel.query.filter_by(
|
||||||
|
message_model_id=message_model.id
|
||||||
|
).all()
|
||||||
|
|
||||||
# do any waiting message instances have matching correlations?
|
# do any waiting message instances have matching correlations?
|
||||||
matching_message = None
|
matching_message = None
|
||||||
|
@ -109,14 +109,21 @@ def message_send(
|
||||||
|
|
||||||
process_instance = None
|
process_instance = None
|
||||||
if matching_message:
|
if matching_message:
|
||||||
process_instance = ProcessInstanceModel.query.filter_by(id = matching_message.process_instance_id).first()
|
process_instance = ProcessInstanceModel.query.filter_by(
|
||||||
|
id=matching_message.process_instance_id
|
||||||
|
).first()
|
||||||
|
|
||||||
if matching_message and process_instance and process_instance.status != ProcessInstanceStatus.waiting.value:
|
if (
|
||||||
|
matching_message
|
||||||
|
and process_instance
|
||||||
|
and process_instance.status != ProcessInstanceStatus.waiting.value
|
||||||
|
):
|
||||||
raise ApiError(
|
raise ApiError(
|
||||||
error_code="message_not_accepted",
|
error_code="message_not_accepted",
|
||||||
message=(
|
message=(
|
||||||
f"The process that can accept message '{message_identifier}' with the given correlation keys"
|
f"The process that can accept message '{message_identifier}' with the"
|
||||||
f" is not currently waiting for that message. It is currently in the a '{process_instance.status}' state."
|
" given correlation keys is not currently waiting for that message. "
|
||||||
|
f" It is currently in the a '{process_instance.status}' state."
|
||||||
),
|
),
|
||||||
status_code=400,
|
status_code=400,
|
||||||
)
|
)
|
||||||
|
@ -136,8 +143,10 @@ def message_send(
|
||||||
ApiError(
|
ApiError(
|
||||||
error_code="cannot_start_message",
|
error_code="cannot_start_message",
|
||||||
message=(
|
message=(
|
||||||
f"No process instances correlate with the given message id of '{message_identifier}'. "
|
"No process instances correlate with the given message id of"
|
||||||
f"And this message name is not currently associated with any process Start Event."),
|
f" '{message_identifier}'. And this message name is not"
|
||||||
|
" currently associated with any process Start Event."
|
||||||
|
),
|
||||||
status_code=400,
|
status_code=400,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,13 +2,9 @@
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from sqlalchemy import and_
|
|
||||||
from sqlalchemy import or_
|
|
||||||
from sqlalchemy import select
|
|
||||||
|
|
||||||
from spiffworkflow_backend.models.db import db
|
from spiffworkflow_backend.models.db import db
|
||||||
from spiffworkflow_backend.models.message_correlation import MessageCorrelationModel
|
from spiffworkflow_backend.models.message_instance import MessageInstanceModel
|
||||||
from spiffworkflow_backend.models.message_instance import MessageInstanceModel, MessageStatuses
|
from spiffworkflow_backend.models.message_instance import MessageStatuses
|
||||||
from spiffworkflow_backend.models.message_triggerable_process_model import (
|
from spiffworkflow_backend.models.message_triggerable_process_model import (
|
||||||
MessageTriggerableProcessModel,
|
MessageTriggerableProcessModel,
|
||||||
)
|
)
|
||||||
|
@ -121,8 +117,7 @@ class MessageService:
|
||||||
processor_receive = ProcessInstanceProcessor(process_instance_receive)
|
processor_receive = ProcessInstanceProcessor(process_instance_receive)
|
||||||
processor_receive.do_engine_steps(save=False)
|
processor_receive.do_engine_steps(save=False)
|
||||||
processor_receive.bpmn_process_instance.catch_bpmn_message(
|
processor_receive.bpmn_process_instance.catch_bpmn_message(
|
||||||
message_model_name,
|
message_model_name, message_payload
|
||||||
message_payload
|
|
||||||
)
|
)
|
||||||
processor_receive.do_engine_steps(save=True)
|
processor_receive.do_engine_steps(save=True)
|
||||||
|
|
||||||
|
@ -149,7 +144,6 @@ class MessageService:
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
processor_receive = ProcessInstanceProcessor(process_instance_receive)
|
processor_receive = ProcessInstanceProcessor(process_instance_receive)
|
||||||
processor_receive.bpmn_process_instance.catch_bpmn_message(
|
processor_receive.bpmn_process_instance.catch_bpmn_message(
|
||||||
message_model_name,
|
message_model_name,
|
||||||
|
|
|
@ -1340,7 +1340,6 @@ class ProcessInstanceProcessor:
|
||||||
|
|
||||||
def process_bpmn_messages(self) -> None:
|
def process_bpmn_messages(self) -> None:
|
||||||
"""Process_bpmn_messages."""
|
"""Process_bpmn_messages."""
|
||||||
|
|
||||||
bpmn_messages = self.bpmn_process_instance.get_bpmn_messages()
|
bpmn_messages = self.bpmn_process_instance.get_bpmn_messages()
|
||||||
for bpmn_message in bpmn_messages:
|
for bpmn_message in bpmn_messages:
|
||||||
# only message sends are in get_bpmn_messages
|
# only message sends are in get_bpmn_messages
|
||||||
|
@ -1351,7 +1350,6 @@ class ProcessInstanceProcessor:
|
||||||
f"Invalid message name: {bpmn_message.name}.",
|
f"Invalid message name: {bpmn_message.name}.",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
if not bpmn_message.correlations:
|
if not bpmn_message.correlations:
|
||||||
raise ApiError(
|
raise ApiError(
|
||||||
"message_correlations_missing",
|
"message_correlations_missing",
|
||||||
|
@ -1362,8 +1360,10 @@ class ProcessInstanceProcessor:
|
||||||
)
|
)
|
||||||
|
|
||||||
message_correlations = []
|
message_correlations = []
|
||||||
for (name, value) in bpmn_message.correlations.items():
|
for name, value in bpmn_message.correlations.items():
|
||||||
message_correlation_property = message_model.get_correlation_property(name)
|
message_correlation_property = message_model.get_correlation_property(
|
||||||
|
name
|
||||||
|
)
|
||||||
if message_correlation_property is None:
|
if message_correlation_property is None:
|
||||||
raise ApiError(
|
raise ApiError(
|
||||||
"message_correlations_missing_from_process",
|
"message_correlations_missing_from_process",
|
||||||
|
@ -1372,17 +1372,20 @@ class ProcessInstanceProcessor:
|
||||||
f" identifier:{name}"
|
f" identifier:{name}"
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
message_correlations.append(MessageCorrelationModel(
|
message_correlations.append(
|
||||||
process_instance_id=self.process_instance_model.id,
|
MessageCorrelationModel(
|
||||||
message_correlation_property_id=message_correlation_property.id,
|
process_instance_id=self.process_instance_model.id,
|
||||||
name=name,
|
message_correlation_property_id=message_correlation_property.id,
|
||||||
value=value))
|
name=name,
|
||||||
|
value=value,
|
||||||
|
)
|
||||||
|
)
|
||||||
message_instance = MessageInstanceModel(
|
message_instance = MessageInstanceModel(
|
||||||
process_instance_id=self.process_instance_model.id,
|
process_instance_id=self.process_instance_model.id,
|
||||||
message_type="send",
|
message_type="send",
|
||||||
message_model_id=message_model.id,
|
message_model_id=message_model.id,
|
||||||
payload=bpmn_message.payload,
|
payload=bpmn_message.payload,
|
||||||
message_correlations=message_correlations
|
message_correlations=message_correlations,
|
||||||
)
|
)
|
||||||
db.session.add(message_instance)
|
db.session.add(message_instance)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
@ -1434,15 +1437,29 @@ class ProcessInstanceProcessor:
|
||||||
for (
|
for (
|
||||||
spiff_correlation_property
|
spiff_correlation_property
|
||||||
) in waiting_task.task_spec.event_definition.correlation_properties:
|
) in waiting_task.task_spec.event_definition.correlation_properties:
|
||||||
message_correlation = next((mc for mc in message_instance.message_correlations
|
message_correlation = next(
|
||||||
if mc.name == spiff_correlation_property.name), None)
|
(
|
||||||
|
mc
|
||||||
|
for mc in message_instance.message_correlations
|
||||||
|
if mc.name == spiff_correlation_property.name
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
)
|
||||||
if not message_correlation:
|
if not message_correlation:
|
||||||
expression = spiff_correlation_property.expression
|
expression = spiff_correlation_property.expression
|
||||||
correlation_value = ProcessInstanceProcessor._script_engine.evaluate(waiting_task, expression)
|
correlation_value = (
|
||||||
|
ProcessInstanceProcessor._script_engine.evaluate(
|
||||||
|
waiting_task, expression
|
||||||
|
)
|
||||||
|
)
|
||||||
correlation_name = spiff_correlation_property.name
|
correlation_name = spiff_correlation_property.name
|
||||||
message_prop = MessageCorrelationPropertyModel.query.\
|
message_prop = (
|
||||||
filter_by(identifier=correlation_name).\
|
MessageCorrelationPropertyModel.query.filter_by(
|
||||||
filter_by(message_model_id=message_model.id).first()
|
identifier=correlation_name
|
||||||
|
)
|
||||||
|
.filter_by(message_model_id=message_model.id)
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
|
||||||
message_correlation = MessageCorrelationModel(
|
message_correlation = MessageCorrelationModel(
|
||||||
process_instance_id=self.process_instance_model.id,
|
process_instance_id=self.process_instance_model.id,
|
||||||
|
|
|
@ -175,7 +175,7 @@ class SpecFileService(FileSystemService):
|
||||||
"""Validate_bpmn_xml."""
|
"""Validate_bpmn_xml."""
|
||||||
file_type = FileSystemService.file_type(file_name)
|
file_type = FileSystemService.file_type(file_name)
|
||||||
if file_type.value == FileType.bpmn.value:
|
if file_type.value == FileType.bpmn.value:
|
||||||
validator = BpmnValidator()
|
BpmnValidator()
|
||||||
parser = MyCustomParser()
|
parser = MyCustomParser()
|
||||||
try:
|
try:
|
||||||
parser.add_bpmn_xml(
|
parser.add_bpmn_xml(
|
||||||
|
|
|
@ -150,4 +150,4 @@ It will fire a message connected to the invoice keys above, starting another pro
|
||||||
</bpmndi:BPMNEdge>
|
</bpmndi:BPMNEdge>
|
||||||
</bpmndi:BPMNPlane>
|
</bpmndi:BPMNPlane>
|
||||||
</bpmndi:BPMNDiagram>
|
</bpmndi:BPMNDiagram>
|
||||||
</bpmn:definitions>
|
</bpmn:definitions>
|
||||||
|
|
|
@ -150,4 +150,4 @@ It will fire a message connected to the invoice keys above, starting another pro
|
||||||
</bpmndi:BPMNEdge>
|
</bpmndi:BPMNEdge>
|
||||||
</bpmndi:BPMNPlane>
|
</bpmndi:BPMNPlane>
|
||||||
</bpmndi:BPMNDiagram>
|
</bpmndi:BPMNDiagram>
|
||||||
</bpmn:definitions>
|
</bpmn:definitions>
|
||||||
|
|
|
@ -1352,7 +1352,7 @@ class TestProcessApi(BaseTest):
|
||||||
"customer_id": "sartography",
|
"customer_id": "sartography",
|
||||||
"po_number": "1001",
|
"po_number": "1001",
|
||||||
"amount": "One Billion Dollars! Mwhahahahahaha",
|
"amount": "One Billion Dollars! Mwhahahahahaha",
|
||||||
"description": "But seriously."
|
"description": "But seriously.",
|
||||||
}
|
}
|
||||||
response = client.post(
|
response = client.post(
|
||||||
f"/v1.0/messages/{message_model_identifier}",
|
f"/v1.0/messages/{message_model_identifier}",
|
||||||
|
@ -1401,7 +1401,7 @@ class TestProcessApi(BaseTest):
|
||||||
"customer_id": "sartography",
|
"customer_id": "sartography",
|
||||||
"po_number": "1001",
|
"po_number": "1001",
|
||||||
"amount": "One Billion Dollars! Mwhahahahahaha",
|
"amount": "One Billion Dollars! Mwhahahahahaha",
|
||||||
"description": "Ya!, a-ok bud!"
|
"description": "Ya!, a-ok bud!",
|
||||||
}
|
}
|
||||||
response = self.create_process_instance_from_process_model_id_with_api(
|
response = self.create_process_instance_from_process_model_id_with_api(
|
||||||
client,
|
client,
|
||||||
|
@ -1417,14 +1417,13 @@ class TestProcessApi(BaseTest):
|
||||||
)
|
)
|
||||||
assert response.json is not None
|
assert response.json is not None
|
||||||
|
|
||||||
process_instance = ProcessInstanceModel.query.filter_by(id=process_instance_id).first()
|
process_instance = ProcessInstanceModel.query.filter_by(
|
||||||
|
id=process_instance_id
|
||||||
|
).first()
|
||||||
processor = ProcessInstanceProcessor(process_instance)
|
processor = ProcessInstanceProcessor(process_instance)
|
||||||
processor.do_engine_steps(save=True)
|
processor.do_engine_steps(save=True)
|
||||||
task = processor.get_all_user_tasks()[0]
|
task = processor.get_all_user_tasks()[0]
|
||||||
human_task = process_instance.active_human_tasks[0]
|
human_task = process_instance.active_human_tasks[0]
|
||||||
spiff_task = processor.__class__.get_task_by_bpmn_identifier(
|
|
||||||
human_task.task_name, processor.bpmn_process_instance
|
|
||||||
)
|
|
||||||
|
|
||||||
ProcessInstanceService.complete_form_task(
|
ProcessInstanceService.complete_form_task(
|
||||||
processor,
|
processor,
|
||||||
|
@ -1484,7 +1483,7 @@ class TestProcessApi(BaseTest):
|
||||||
"customer_id": "sartography",
|
"customer_id": "sartography",
|
||||||
"po_number": "1001",
|
"po_number": "1001",
|
||||||
"amount": "One Billion Dollars! Mwhahahahahaha",
|
"amount": "One Billion Dollars! Mwhahahahahaha",
|
||||||
"description": "But seriously."
|
"description": "But seriously.",
|
||||||
}
|
}
|
||||||
|
|
||||||
response = self.create_process_instance_from_process_model_id_with_api(
|
response = self.create_process_instance_from_process_model_id_with_api(
|
||||||
|
@ -1495,7 +1494,6 @@ class TestProcessApi(BaseTest):
|
||||||
assert response.json is not None
|
assert response.json is not None
|
||||||
process_instance_id = response.json["id"]
|
process_instance_id = response.json["id"]
|
||||||
|
|
||||||
|
|
||||||
process_instance = ProcessInstanceModel.query.filter_by(
|
process_instance = ProcessInstanceModel.query.filter_by(
|
||||||
id=process_instance_id
|
id=process_instance_id
|
||||||
).first()
|
).first()
|
||||||
|
@ -1503,9 +1501,6 @@ class TestProcessApi(BaseTest):
|
||||||
processor.do_engine_steps(save=True)
|
processor.do_engine_steps(save=True)
|
||||||
task = processor.get_all_user_tasks()[0]
|
task = processor.get_all_user_tasks()[0]
|
||||||
human_task = process_instance.active_human_tasks[0]
|
human_task = process_instance.active_human_tasks[0]
|
||||||
spiff_task = processor.__class__.get_task_by_bpmn_identifier(
|
|
||||||
human_task.task_name, processor.bpmn_process_instance
|
|
||||||
)
|
|
||||||
|
|
||||||
ProcessInstanceService.complete_form_task(
|
ProcessInstanceService.complete_form_task(
|
||||||
processor,
|
processor,
|
||||||
|
@ -1517,7 +1512,7 @@ class TestProcessApi(BaseTest):
|
||||||
processor.save()
|
processor.save()
|
||||||
|
|
||||||
processor.suspend()
|
processor.suspend()
|
||||||
payload['description'] = "Message To Suspended"
|
payload["description"] = "Message To Suspended"
|
||||||
response = client.post(
|
response = client.post(
|
||||||
f"/v1.0/messages/{message_model_identifier}",
|
f"/v1.0/messages/{message_model_identifier}",
|
||||||
content_type="application/json",
|
content_type="application/json",
|
||||||
|
@ -1531,14 +1526,12 @@ class TestProcessApi(BaseTest):
|
||||||
assert response.json["error_code"] == "message_not_accepted"
|
assert response.json["error_code"] == "message_not_accepted"
|
||||||
|
|
||||||
processor.resume()
|
processor.resume()
|
||||||
payload['description'] = "Message To Resumed"
|
payload["description"] = "Message To Resumed"
|
||||||
response = client.post(
|
response = client.post(
|
||||||
f"/v1.0/messages/{message_model_identifier}",
|
f"/v1.0/messages/{message_model_identifier}",
|
||||||
content_type="application/json",
|
content_type="application/json",
|
||||||
headers=self.logged_in_headers(with_super_admin_user),
|
headers=self.logged_in_headers(with_super_admin_user),
|
||||||
data=json.dumps(
|
data=json.dumps({"payload": payload}),
|
||||||
{"payload": payload}
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
json_data = response.json
|
json_data = response.json
|
||||||
|
@ -2325,7 +2318,7 @@ class TestProcessApi(BaseTest):
|
||||||
"customer_id": "sartography",
|
"customer_id": "sartography",
|
||||||
"po_number": "1001",
|
"po_number": "1001",
|
||||||
"amount": "One Billion Dollars! Mwhahahahahaha",
|
"amount": "One Billion Dollars! Mwhahahahahaha",
|
||||||
"description": "But seriously."
|
"description": "But seriously.",
|
||||||
}
|
}
|
||||||
response = client.post(
|
response = client.post(
|
||||||
f"/v1.0/messages/{message_model_identifier}",
|
f"/v1.0/messages/{message_model_identifier}",
|
||||||
|
|
|
@ -2,16 +2,14 @@
|
||||||
import pytest
|
import pytest
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
from flask.testing import FlaskClient
|
from flask.testing import FlaskClient
|
||||||
|
|
||||||
from spiffworkflow_backend.exceptions.api_error import ApiError
|
|
||||||
from spiffworkflow_backend.routes.messages_controller import message_send
|
|
||||||
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
|
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
|
||||||
from tests.spiffworkflow_backend.helpers.test_data import load_test_spec
|
from tests.spiffworkflow_backend.helpers.test_data import load_test_spec
|
||||||
|
|
||||||
from spiffworkflow_backend.models.message_correlation import MessageCorrelationModel
|
from spiffworkflow_backend.exceptions.api_error import ApiError
|
||||||
from spiffworkflow_backend.models.message_instance import MessageInstanceModel
|
from spiffworkflow_backend.models.message_instance import MessageInstanceModel
|
||||||
from spiffworkflow_backend.models.process_instance import ProcessInstanceModel
|
from spiffworkflow_backend.models.process_instance import ProcessInstanceModel
|
||||||
from spiffworkflow_backend.models.user import UserModel
|
from spiffworkflow_backend.models.user import UserModel
|
||||||
|
from spiffworkflow_backend.routes.messages_controller import message_send
|
||||||
from spiffworkflow_backend.services.message_service import MessageService
|
from spiffworkflow_backend.services.message_service import MessageService
|
||||||
from spiffworkflow_backend.services.process_instance_processor import (
|
from spiffworkflow_backend.services.process_instance_processor import (
|
||||||
ProcessInstanceProcessor,
|
ProcessInstanceProcessor,
|
||||||
|
@ -25,22 +23,24 @@ class TestMessageService(BaseTest):
|
||||||
"""TestMessageService."""
|
"""TestMessageService."""
|
||||||
|
|
||||||
def test_message_from_api_into_running_process(
|
def test_message_from_api_into_running_process(
|
||||||
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:
|
||||||
"""This example workflow will send a message called 'request_approval' and then wait for a response message
|
"""Test sending a message to a running process via the API.
|
||||||
of 'approval_result'. This test assures that it will fire the message with the correct correlation properties
|
|
||||||
and will respond only to a message called "approval_result' that has the matching correlation properties,
|
|
||||||
as sent by an API Call"""
|
|
||||||
|
|
||||||
|
This example workflow will send a message called 'request_approval' and then wait for a response message
|
||||||
|
of 'approval_result'. This test assures that it will fire the message with the correct correlation properties
|
||||||
|
and will respond only to a message called 'approval_result' that has the matching correlation properties,
|
||||||
|
as sent by an API Call.
|
||||||
|
"""
|
||||||
self.payload = {
|
self.payload = {
|
||||||
"customer_id": "Sartography",
|
"customer_id": "Sartography",
|
||||||
"po_number": 1001,
|
"po_number": 1001,
|
||||||
"description": "We built a new feature for messages!",
|
"description": "We built a new feature for messages!",
|
||||||
"amount": "100.00"
|
"amount": "100.00",
|
||||||
}
|
}
|
||||||
|
|
||||||
self.start_sender_process(client, with_super_admin_user)
|
self.start_sender_process(client, with_super_admin_user)
|
||||||
|
@ -49,49 +49,59 @@ class TestMessageService(BaseTest):
|
||||||
|
|
||||||
# Make an API call to the service endpoint, but use the wrong po number
|
# Make an API call to the service endpoint, but use the wrong po number
|
||||||
with pytest.raises(ApiError):
|
with pytest.raises(ApiError):
|
||||||
message_send("approval_result", {'payload': {'po_number': 5001}})
|
message_send("approval_result", {"payload": {"po_number": 5001}})
|
||||||
|
|
||||||
# Sound return an error when making an API call for right po number, wrong client
|
# Sound return an error when making an API call for right po number, wrong client
|
||||||
with pytest.raises(ApiError):
|
with pytest.raises(ApiError):
|
||||||
message_send("approval_result", {'payload': {'po_number': 1001, 'customer_id': 'jon'}})
|
message_send(
|
||||||
|
"approval_result",
|
||||||
|
{"payload": {"po_number": 1001, "customer_id": "jon"}},
|
||||||
|
)
|
||||||
|
|
||||||
# No error when calling with the correct parameters
|
# No error when calling with the correct parameters
|
||||||
response = message_send("approval_result", {'payload': {'po_number': 1001, 'customer_id': 'Sartography'}})
|
message_send(
|
||||||
|
"approval_result",
|
||||||
|
{"payload": {"po_number": 1001, "customer_id": "Sartography"}},
|
||||||
|
)
|
||||||
|
|
||||||
# There is no longer a waiting message
|
# There is no longer a waiting message
|
||||||
waiting_messages = MessageInstanceModel.query. \
|
waiting_messages = (
|
||||||
filter_by(message_type="receive"). \
|
MessageInstanceModel.query.filter_by(message_type="receive")
|
||||||
filter_by(status="ready"). \
|
.filter_by(status="ready")
|
||||||
filter_by(process_instance_id=self.process_instance.id).all()
|
.filter_by(process_instance_id=self.process_instance.id)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
assert len(waiting_messages) == 0
|
assert len(waiting_messages) == 0
|
||||||
|
|
||||||
# The process has completed
|
# The process has completed
|
||||||
assert self.process_instance.status == 'complete'
|
assert self.process_instance.status == "complete"
|
||||||
|
|
||||||
def test_single_conversation_between_two_processes(
|
def test_single_conversation_between_two_processes(
|
||||||
self,
|
self,
|
||||||
app: Flask,
|
app: Flask,
|
||||||
client: FlaskClient,
|
client: FlaskClient,
|
||||||
with_db_and_bpmn_file_cleanup: None,
|
with_super_admin_user: UserModel,
|
||||||
with_super_admin_user: UserModel,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Assure that communication between two processes works the same as making a call through the API, here
|
"""Test messages between two different running processes using a single conversation.
|
||||||
|
|
||||||
|
Assure that communication between two processes works the same as making a call through the API, here
|
||||||
we have two process instances that are communicating with each other using one conversation about an
|
we have two process instances that are communicating with each other using one conversation about an
|
||||||
Invoice whose details are defined in the following message payload """
|
Invoice whose details are defined in the following message payload
|
||||||
|
"""
|
||||||
self.payload = {
|
self.payload = {
|
||||||
"customer_id": "Sartography",
|
"customer_id": "Sartography",
|
||||||
"po_number": 1001,
|
"po_number": 1001,
|
||||||
"description": "We built a new feature for messages!",
|
"description": "We built a new feature for messages!",
|
||||||
"amount": "100.00"
|
"amount": "100.00",
|
||||||
}
|
}
|
||||||
|
|
||||||
# Load up the definition for the receiving process (it has a message start event that should cause it to
|
# Load up the definition for the receiving process (it has a message start event that should cause it to
|
||||||
# fire when a unique message comes through.
|
# fire when a unique message comes through.
|
||||||
# Fire up the first process
|
# Fire up the first process
|
||||||
second_process_model = load_test_spec(
|
load_test_spec(
|
||||||
"test_group/message_receive",
|
"test_group/message_receive",
|
||||||
process_model_source_directory="message_send_one_conversation",
|
process_model_source_directory="message_send_one_conversation",
|
||||||
bpmn_file_name="message_receiver.bpmn"
|
bpmn_file_name="message_receiver.bpmn",
|
||||||
)
|
)
|
||||||
|
|
||||||
# Now start the main process
|
# Now start the main process
|
||||||
|
@ -110,30 +120,29 @@ class TestMessageService(BaseTest):
|
||||||
# it will deliver the message that was sent from the receiver back to the original sender.
|
# it will deliver the message that was sent from the receiver back to the original sender.
|
||||||
MessageService.process_message_instances()
|
MessageService.process_message_instances()
|
||||||
|
|
||||||
|
|
||||||
# But there should be no send message waiting for delivery, because
|
# But there should be no send message waiting for delivery, because
|
||||||
# the message receiving process should pick it up instantly via
|
# the message receiving process should pick it up instantly via
|
||||||
# it's start event.
|
# it's start event.
|
||||||
waiting_messages = MessageInstanceModel.query. \
|
waiting_messages = (
|
||||||
filter_by(message_type="receive"). \
|
MessageInstanceModel.query.filter_by(message_type="receive")
|
||||||
filter_by(status="ready"). \
|
.filter_by(status="ready")
|
||||||
filter_by(process_instance_id=self.process_instance.id).all()
|
.filter_by(process_instance_id=self.process_instance.id)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
assert len(waiting_messages) == 0
|
assert len(waiting_messages) == 0
|
||||||
|
|
||||||
# The message sender process is complete
|
# The message sender process is complete
|
||||||
assert self.process_instance.status == 'complete'
|
assert self.process_instance.status == "complete"
|
||||||
|
|
||||||
# The message receiver process is also complete
|
# The message receiver process is also complete
|
||||||
message_receiver_process = ProcessInstanceModel.query.filter_by(process_model_identifier = "test_group/message_receive").first()
|
message_receiver_process = ProcessInstanceModel.query.filter_by(
|
||||||
assert message_receiver_process.status == 'complete'
|
process_model_identifier="test_group/message_receive"
|
||||||
|
).first()
|
||||||
|
assert message_receiver_process.status == "complete"
|
||||||
|
|
||||||
|
def start_sender_process(
|
||||||
|
self, client: FlaskClient, with_super_admin_user: UserModel
|
||||||
|
) -> None:
|
||||||
|
|
||||||
def start_sender_process(self,
|
|
||||||
client: FlaskClient,
|
|
||||||
with_super_admin_user: UserModel):
|
|
||||||
process_group_id = "test_group"
|
process_group_id = "test_group"
|
||||||
self.create_process_group(
|
self.create_process_group(
|
||||||
client, with_super_admin_user, process_group_id, process_group_id
|
client, with_super_admin_user, process_group_id, process_group_id
|
||||||
|
@ -153,9 +162,6 @@ class TestMessageService(BaseTest):
|
||||||
processor_send_receive.do_engine_steps(save=True)
|
processor_send_receive.do_engine_steps(save=True)
|
||||||
task = processor_send_receive.get_all_user_tasks()[0]
|
task = processor_send_receive.get_all_user_tasks()[0]
|
||||||
human_task = self.process_instance.active_human_tasks[0]
|
human_task = self.process_instance.active_human_tasks[0]
|
||||||
spiff_task = processor_send_receive.__class__.get_task_by_bpmn_identifier(
|
|
||||||
human_task.task_name, processor_send_receive.bpmn_process_instance
|
|
||||||
)
|
|
||||||
|
|
||||||
ProcessInstanceService.complete_form_task(
|
ProcessInstanceService.complete_form_task(
|
||||||
processor_send_receive,
|
processor_send_receive,
|
||||||
|
@ -166,39 +172,49 @@ class TestMessageService(BaseTest):
|
||||||
)
|
)
|
||||||
processor_send_receive.save()
|
processor_send_receive.save()
|
||||||
|
|
||||||
def assure_a_message_was_sent(self):
|
def assure_a_message_was_sent(self) -> None:
|
||||||
# There should be one new send message for the given process instance.
|
# There should be one new send message for the given process instance.
|
||||||
send_messages = MessageInstanceModel.query. \
|
send_messages = (
|
||||||
filter_by(message_type="send"). \
|
MessageInstanceModel.query.filter_by(message_type="send")
|
||||||
filter_by(process_instance_id=self.process_instance.id).all()
|
.filter_by(process_instance_id=self.process_instance.id)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
assert len(send_messages) == 1
|
assert len(send_messages) == 1
|
||||||
send_message = send_messages[0]
|
send_message = send_messages[0]
|
||||||
|
|
||||||
# The payload should match because of how it is written in the Send task.
|
# The payload should match because of how it is written in the Send task.
|
||||||
assert send_message.payload == self.payload, "The send message should match up with the payload"
|
assert (
|
||||||
|
send_message.payload == self.payload
|
||||||
|
), "The send message should match up with the payload"
|
||||||
assert send_message.message_model.identifier == "request_approval"
|
assert send_message.message_model.identifier == "request_approval"
|
||||||
assert send_message.status == "ready"
|
assert send_message.status == "ready"
|
||||||
assert len(send_message.message_correlations) == 2
|
assert len(send_message.message_correlations) == 2
|
||||||
message_instance_result = MessageInstanceModel.query.all()
|
MessageInstanceModel.query.all()
|
||||||
self.assure_correlation_properties_are_right(send_message)
|
self.assure_correlation_properties_are_right(send_message)
|
||||||
|
|
||||||
def assure_there_is_a_process_waiting_on_a_message(self):
|
def assure_there_is_a_process_waiting_on_a_message(self) -> None:
|
||||||
# There should be one new send message for the given process instance.
|
# There should be one new send message for the given process instance.
|
||||||
waiting_messages = MessageInstanceModel.query. \
|
waiting_messages = (
|
||||||
filter_by(message_type="receive"). \
|
MessageInstanceModel.query.filter_by(message_type="receive")
|
||||||
filter_by(status="ready"). \
|
.filter_by(status="ready")
|
||||||
filter_by(process_instance_id=self.process_instance.id).all()
|
.filter_by(process_instance_id=self.process_instance.id)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
assert len(waiting_messages) == 1
|
assert len(waiting_messages) == 1
|
||||||
waiting_message = waiting_messages[0]
|
waiting_message = waiting_messages[0]
|
||||||
self.assure_correlation_properties_are_right(waiting_message)
|
self.assure_correlation_properties_are_right(waiting_message)
|
||||||
|
|
||||||
def assure_correlation_properties_are_right(self, message):
|
def assure_correlation_properties_are_right(
|
||||||
|
self, message: MessageInstanceModel
|
||||||
|
) -> None:
|
||||||
# Correlation Properties should match up
|
# Correlation Properties should match up
|
||||||
po_curr = next(c for c in message.message_correlations if c.name == "po_number")
|
po_curr = next(c for c in message.message_correlations if c.name == "po_number")
|
||||||
customer_curr = next(c for c in message.message_correlations if c.name == "customer_id")
|
customer_curr = next(
|
||||||
|
c for c in message.message_correlations if c.name == "customer_id"
|
||||||
|
)
|
||||||
assert po_curr is not None
|
assert po_curr is not None
|
||||||
assert customer_curr is not None
|
assert customer_curr is not None
|
||||||
assert po_curr.value == '1001'
|
assert po_curr.value == "1001"
|
||||||
assert customer_curr.value == "Sartography"
|
assert customer_curr.value == "Sartography"
|
||||||
|
|
||||||
def test_can_send_message_to_multiple_process_models(
|
def test_can_send_message_to_multiple_process_models(
|
||||||
|
@ -209,7 +225,7 @@ class TestMessageService(BaseTest):
|
||||||
with_super_admin_user: UserModel,
|
with_super_admin_user: UserModel,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test_can_send_message_to_multiple_process_models."""
|
"""Test_can_send_message_to_multiple_process_models."""
|
||||||
process_group_id = "test_group"
|
process_group_id = "test_group_multi"
|
||||||
self.create_process_group(
|
self.create_process_group(
|
||||||
client, with_super_admin_user, process_group_id, process_group_id
|
client, with_super_admin_user, process_group_id, process_group_id
|
||||||
)
|
)
|
||||||
|
@ -233,8 +249,8 @@ class TestMessageService(BaseTest):
|
||||||
user = self.find_or_create_user()
|
user = self.find_or_create_user()
|
||||||
|
|
||||||
process_instance_sender = ProcessInstanceService.create_process_instance_from_process_model_identifier(
|
process_instance_sender = ProcessInstanceService.create_process_instance_from_process_model_identifier(
|
||||||
process_model_sender.id,
|
process_model_sender.id, user
|
||||||
user)
|
)
|
||||||
|
|
||||||
processor_sender = ProcessInstanceProcessor(process_instance_sender)
|
processor_sender = ProcessInstanceProcessor(process_instance_sender)
|
||||||
processor_sender.do_engine_steps()
|
processor_sender.do_engine_steps()
|
||||||
|
@ -243,9 +259,18 @@ class TestMessageService(BaseTest):
|
||||||
# At this point, the message_sender process has fired two different messages but those
|
# At this point, the message_sender process has fired two different messages but those
|
||||||
# processes have not started, and it is now paused, waiting for to receive a message. so
|
# processes have not started, and it is now paused, waiting for to receive a message. so
|
||||||
# we should have two sends and a receive.
|
# we should have two sends and a receive.
|
||||||
assert MessageInstanceModel.query.filter_by(process_instance_id = process_instance_sender.id).count() == 3
|
assert (
|
||||||
assert MessageInstanceModel.query.count() == 3 # all messages are related to the instance
|
MessageInstanceModel.query.filter_by(
|
||||||
orig_send_messages = MessageInstanceModel.query.filter_by(message_type="send").all()
|
process_instance_id=process_instance_sender.id
|
||||||
|
).count()
|
||||||
|
== 3
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
MessageInstanceModel.query.count() == 3
|
||||||
|
) # all messages are related to the instance
|
||||||
|
orig_send_messages = MessageInstanceModel.query.filter_by(
|
||||||
|
message_type="send"
|
||||||
|
).all()
|
||||||
assert len(orig_send_messages) == 2
|
assert len(orig_send_messages) == 2
|
||||||
assert MessageInstanceModel.query.filter_by(message_type="receive").count() == 1
|
assert MessageInstanceModel.query.filter_by(message_type="receive").count() == 1
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue