do not raise errors if a process cannot be found in the spec reference cache when trying to get a task trace for an error
This commit is contained in:
parent
d769143c83
commit
f65b301635
|
@ -18,13 +18,13 @@ def setup_database_uri(app: Flask) -> None:
|
||||||
if app.config.get("SPIFFWORKFLOW_BACKEND_DATABASE_URI") is None:
|
if app.config.get("SPIFFWORKFLOW_BACKEND_DATABASE_URI") is None:
|
||||||
database_name = f"spiffworkflow_backend_{app.config['ENV_IDENTIFIER']}"
|
database_name = f"spiffworkflow_backend_{app.config['ENV_IDENTIFIER']}"
|
||||||
if app.config.get("SPIFFWORKFLOW_BACKEND_DATABASE_TYPE") == "sqlite":
|
if app.config.get("SPIFFWORKFLOW_BACKEND_DATABASE_TYPE") == "sqlite":
|
||||||
app.config[
|
app.config["SQLALCHEMY_DATABASE_URI"] = (
|
||||||
"SQLALCHEMY_DATABASE_URI"
|
f"sqlite:///{app.instance_path}/db_{app.config['ENV_IDENTIFIER']}.sqlite3"
|
||||||
] = f"sqlite:///{app.instance_path}/db_{app.config['ENV_IDENTIFIER']}.sqlite3"
|
)
|
||||||
elif app.config.get("SPIFFWORKFLOW_BACKEND_DATABASE_TYPE") == "postgres":
|
elif app.config.get("SPIFFWORKFLOW_BACKEND_DATABASE_TYPE") == "postgres":
|
||||||
app.config[
|
app.config["SQLALCHEMY_DATABASE_URI"] = (
|
||||||
"SQLALCHEMY_DATABASE_URI"
|
f"postgresql://spiffworkflow_backend:spiffworkflow_backend@localhost:5432/{database_name}"
|
||||||
] = f"postgresql://spiffworkflow_backend:spiffworkflow_backend@localhost:5432/{database_name}"
|
)
|
||||||
else:
|
else:
|
||||||
# use pswd to trick flake8 with hardcoded passwords
|
# use pswd to trick flake8 with hardcoded passwords
|
||||||
db_pswd = app.config.get("SPIFFWORKFLOW_BACKEND_DATABASE_PASSWORD")
|
db_pswd = app.config.get("SPIFFWORKFLOW_BACKEND_DATABASE_PASSWORD")
|
||||||
|
|
|
@ -127,8 +127,8 @@ class ApiError(Exception):
|
||||||
instance.task_trace = TaskModelError.get_task_trace(task_model)
|
instance.task_trace = TaskModelError.get_task_trace(task_model)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
spec_reference = TaskService.get_spec_reference_from_bpmn_process(task_model.bpmn_process)
|
spec_reference_filename = TaskService.get_spec_filename_from_bpmn_process(task_model.bpmn_process)
|
||||||
instance.file_name = spec_reference.file_name
|
instance.file_name = spec_reference_filename
|
||||||
except Exception as exception:
|
except Exception as exception:
|
||||||
current_app.logger.error(exception)
|
current_app.logger.error(exception)
|
||||||
|
|
||||||
|
|
|
@ -129,9 +129,9 @@ class ProcessInstanceModel(SpiffworkflowBaseDBModel):
|
||||||
def serialized_with_metadata(self) -> dict[str, Any]:
|
def serialized_with_metadata(self) -> dict[str, Any]:
|
||||||
process_instance_attributes = self.serialized
|
process_instance_attributes = self.serialized
|
||||||
process_instance_attributes["process_metadata"] = self.process_metadata
|
process_instance_attributes["process_metadata"] = self.process_metadata
|
||||||
process_instance_attributes[
|
process_instance_attributes["process_model_with_diagram_identifier"] = (
|
||||||
"process_model_with_diagram_identifier"
|
self.process_model_with_diagram_identifier
|
||||||
] = self.process_model_with_diagram_identifier
|
)
|
||||||
return process_instance_attributes
|
return process_instance_attributes
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -423,9 +423,9 @@ class ProcessInstanceProcessor:
|
||||||
tld.process_instance_id = process_instance_model.id
|
tld.process_instance_id = process_instance_model.id
|
||||||
|
|
||||||
# we want this to be the fully qualified path to the process model including all group subcomponents
|
# we want this to be the fully qualified path to the process model including all group subcomponents
|
||||||
current_app.config[
|
current_app.config["THREAD_LOCAL_DATA"].process_model_identifier = (
|
||||||
"THREAD_LOCAL_DATA"
|
f"{process_instance_model.process_model_identifier}"
|
||||||
].process_model_identifier = f"{process_instance_model.process_model_identifier}"
|
)
|
||||||
|
|
||||||
self.process_instance_model = process_instance_model
|
self.process_instance_model = process_instance_model
|
||||||
self.process_model_service = ProcessModelService()
|
self.process_model_service = ProcessModelService()
|
||||||
|
@ -585,9 +585,9 @@ class ProcessInstanceProcessor:
|
||||||
bpmn_subprocess_definition.bpmn_identifier
|
bpmn_subprocess_definition.bpmn_identifier
|
||||||
] = bpmn_process_definition_dict
|
] = bpmn_process_definition_dict
|
||||||
spiff_bpmn_process_dict["subprocess_specs"][bpmn_subprocess_definition.bpmn_identifier]["task_specs"] = {}
|
spiff_bpmn_process_dict["subprocess_specs"][bpmn_subprocess_definition.bpmn_identifier]["task_specs"] = {}
|
||||||
bpmn_subprocess_definition_bpmn_identifiers[
|
bpmn_subprocess_definition_bpmn_identifiers[bpmn_subprocess_definition.id] = (
|
||||||
bpmn_subprocess_definition.id
|
bpmn_subprocess_definition.bpmn_identifier
|
||||||
] = bpmn_subprocess_definition.bpmn_identifier
|
)
|
||||||
|
|
||||||
task_definitions = TaskDefinitionModel.query.filter(
|
task_definitions = TaskDefinitionModel.query.filter(
|
||||||
TaskDefinitionModel.bpmn_process_definition_id.in_( # type: ignore
|
TaskDefinitionModel.bpmn_process_definition_id.in_( # type: ignore
|
||||||
|
|
|
@ -89,15 +89,15 @@ class TaskModelError(Exception):
|
||||||
task_definition = task_model.task_definition
|
task_definition = task_model.task_definition
|
||||||
task_bpmn_name = TaskService.get_name_for_display(task_definition)
|
task_bpmn_name = TaskService.get_name_for_display(task_definition)
|
||||||
bpmn_process = task_model.bpmn_process
|
bpmn_process = task_model.bpmn_process
|
||||||
spec_reference = TaskService.get_spec_reference_from_bpmn_process(bpmn_process)
|
spec_reference_filename = TaskService.get_spec_filename_from_bpmn_process(bpmn_process)
|
||||||
|
|
||||||
task_trace = [f"{task_bpmn_name} ({spec_reference.file_name})"]
|
task_trace = [f"{task_bpmn_name} ({spec_reference_filename})"]
|
||||||
while bpmn_process.guid is not None:
|
while bpmn_process.guid is not None:
|
||||||
caller_task_model = TaskModel.query.filter_by(guid=bpmn_process.guid).first()
|
caller_task_model = TaskModel.query.filter_by(guid=bpmn_process.guid).first()
|
||||||
bpmn_process = BpmnProcessModel.query.filter_by(id=bpmn_process.direct_parent_process_id).first()
|
bpmn_process = BpmnProcessModel.query.filter_by(id=bpmn_process.direct_parent_process_id).first()
|
||||||
spec_reference = TaskService.get_spec_reference_from_bpmn_process(bpmn_process)
|
spec_reference_filename = TaskService.get_spec_filename_from_bpmn_process(bpmn_process)
|
||||||
task_trace.append(
|
task_trace.append(
|
||||||
f"{TaskService.get_name_for_display(caller_task_model.task_definition)} ({spec_reference.file_name})"
|
f"{TaskService.get_name_for_display(caller_task_model.task_definition)} ({spec_reference_filename})"
|
||||||
)
|
)
|
||||||
return task_trace
|
return task_trace
|
||||||
|
|
||||||
|
@ -630,6 +630,15 @@ class TaskService:
|
||||||
result.append({"event": event_definition, "label": extensions["signalButtonLabel"]})
|
result.append({"event": event_definition, "label": extensions["signalButtonLabel"]})
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_spec_filename_from_bpmn_process(cls, bpmn_process: BpmnProcessModel) -> Optional[str]:
|
||||||
|
"""Just return the filename if the bpmn process is found in spec reference cache."""
|
||||||
|
try:
|
||||||
|
filename: Optional[str] = cls.get_spec_reference_from_bpmn_process(bpmn_process).file_name
|
||||||
|
return filename
|
||||||
|
except SpecReferenceNotFoundError:
|
||||||
|
return None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_spec_reference_from_bpmn_process(cls, bpmn_process: BpmnProcessModel) -> SpecReferenceCache:
|
def get_spec_reference_from_bpmn_process(cls, bpmn_process: BpmnProcessModel) -> SpecReferenceCache:
|
||||||
"""Get the bpmn file for a given task model.
|
"""Get the bpmn file for a given task model.
|
||||||
|
|
|
@ -15,27 +15,6 @@ from spiffworkflow_backend.routes.tasks_controller import _dequeued_interstitial
|
||||||
class TestForGoodErrors(BaseTest):
|
class TestForGoodErrors(BaseTest):
|
||||||
"""Assure when certain errors happen when rendering a jinaj2 error that it makes some sense."""
|
"""Assure when certain errors happen when rendering a jinaj2 error that it makes some sense."""
|
||||||
|
|
||||||
def get_next_user_task(
|
|
||||||
self,
|
|
||||||
process_instance_id: int,
|
|
||||||
client: FlaskClient,
|
|
||||||
with_super_admin_user: UserModel,
|
|
||||||
) -> Any:
|
|
||||||
# Call this to assure all engine-steps are fully processed before we search for human tasks.
|
|
||||||
_dequeued_interstitial_stream(process_instance_id)
|
|
||||||
|
|
||||||
"""Returns the next available user task for a given process instance, if possible."""
|
|
||||||
human_tasks = (
|
|
||||||
db.session.query(HumanTaskModel).filter(HumanTaskModel.process_instance_id == process_instance_id).all()
|
|
||||||
)
|
|
||||||
assert len(human_tasks) > 0, "No human tasks found for process."
|
|
||||||
human_task = human_tasks[0]
|
|
||||||
response = client.get(
|
|
||||||
f"/v1.0/tasks/{process_instance_id}/{human_task.task_id}",
|
|
||||||
headers=self.logged_in_headers(with_super_admin_user),
|
|
||||||
)
|
|
||||||
return response
|
|
||||||
|
|
||||||
def test_invalid_form(
|
def test_invalid_form(
|
||||||
self,
|
self,
|
||||||
app: Flask,
|
app: Flask,
|
||||||
|
@ -61,7 +40,7 @@ class TestForGoodErrors(BaseTest):
|
||||||
headers=self.logged_in_headers(with_super_admin_user),
|
headers=self.logged_in_headers(with_super_admin_user),
|
||||||
)
|
)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
response = self.get_next_user_task(process_instance_id, client, with_super_admin_user)
|
response = self._get_next_user_task(process_instance_id, client, with_super_admin_user)
|
||||||
assert response.json is not None
|
assert response.json is not None
|
||||||
assert response.json["error_type"] == "TemplateSyntaxError"
|
assert response.json["error_type"] == "TemplateSyntaxError"
|
||||||
assert response.json["line_number"] == 3
|
assert response.json["line_number"] == 3
|
||||||
|
@ -88,7 +67,7 @@ class TestForGoodErrors(BaseTest):
|
||||||
f"/v1.0/process-instances/{self.modify_process_identifier_for_path_param(process_model.id)}/{process_instance.id}/run",
|
f"/v1.0/process-instances/{self.modify_process_identifier_for_path_param(process_model.id)}/{process_instance.id}/run",
|
||||||
headers=self.logged_in_headers(with_super_admin_user),
|
headers=self.logged_in_headers(with_super_admin_user),
|
||||||
)
|
)
|
||||||
response = self.get_next_user_task(process_instance.id, client, with_super_admin_user)
|
response = self._get_next_user_task(process_instance.id, client, with_super_admin_user)
|
||||||
|
|
||||||
assert response.status_code == 400
|
assert response.status_code == 400
|
||||||
assert response.json is not None
|
assert response.json is not None
|
||||||
|
@ -99,3 +78,24 @@ class TestForGoodErrors(BaseTest):
|
||||||
assert "instructions for end user" in response.json["message"]
|
assert "instructions for end user" in response.json["message"]
|
||||||
assert "Jinja2" in response.json["message"]
|
assert "Jinja2" in response.json["message"]
|
||||||
assert "unexpected '='" in response.json["message"]
|
assert "unexpected '='" in response.json["message"]
|
||||||
|
|
||||||
|
def _get_next_user_task(
|
||||||
|
self,
|
||||||
|
process_instance_id: int,
|
||||||
|
client: FlaskClient,
|
||||||
|
with_super_admin_user: UserModel,
|
||||||
|
) -> Any:
|
||||||
|
# Call this to assure all engine-steps are fully processed before we search for human tasks.
|
||||||
|
_dequeued_interstitial_stream(process_instance_id)
|
||||||
|
|
||||||
|
"""Returns the next available user task for a given process instance, if possible."""
|
||||||
|
human_tasks = (
|
||||||
|
db.session.query(HumanTaskModel).filter(HumanTaskModel.process_instance_id == process_instance_id).all()
|
||||||
|
)
|
||||||
|
assert len(human_tasks) > 0, "No human tasks found for process."
|
||||||
|
human_task = human_tasks[0]
|
||||||
|
response = client.get(
|
||||||
|
f"/v1.0/tasks/{process_instance_id}/{human_task.task_id}",
|
||||||
|
headers=self.logged_in_headers(with_super_admin_user),
|
||||||
|
)
|
||||||
|
return response
|
||||||
|
|
Loading…
Reference in New Issue