diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/models/human_task.py b/spiffworkflow-backend/src/spiffworkflow_backend/models/human_task.py index bca4cb81e..e66dd59b0 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/models/human_task.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/models/human_task.py @@ -49,6 +49,7 @@ class HumanTaskModel(SpiffworkflowBaseDBModel): # task_id came first which is why it's a string and task_model_id is the int and foreignkey task_model_id: int = db.Column(ForeignKey(TaskModel.id), nullable=True, index=True) # type: ignore + task_model = relationship(TaskModel) task_id: str = db.Column(db.String(50)) task_name: str = db.Column(db.String(255)) task_title: str = db.Column(db.String(50)) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/models/task.py b/spiffworkflow-backend/src/spiffworkflow_backend/models/task.py index 175730591..9fb8d6ffa 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/models/task.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/models/task.py @@ -3,6 +3,7 @@ import enum from dataclasses import dataclass from typing import Any from typing import Optional +from typing import TYPE_CHECKING from typing import Union import marshmallow @@ -18,6 +19,11 @@ from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel from spiffworkflow_backend.models.json_data import JsonDataModel from spiffworkflow_backend.models.task_definition import TaskDefinitionModel +if TYPE_CHECKING: + from spiffworkflow_backend.models.human_task_user import ( # noqa: F401 + HumanTaskModel, + ) + class TaskNotFoundError(Exception): pass @@ -52,6 +58,7 @@ class TaskModel(SpiffworkflowBaseDBModel): guid: str = db.Column(db.String(36), nullable=False, unique=True) bpmn_process_id: int = db.Column(ForeignKey(BpmnProcessModel.id), nullable=False, index=True) # type: ignore bpmn_process = relationship(BpmnProcessModel, back_populates="tasks") + human_tasks = relationship("HumanTaskModel", back_populates="task_model", cascade="delete") process_instance_id: int = db.Column(ForeignKey("process_instance.id"), nullable=False, index=True) # find this by looking up the "workflow_name" and "task_spec" from the properties_json diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_instance_processor.py b/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_instance_processor.py index 2268e0e50..cfdbabd8b 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_instance_processor.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_instance_processor.py @@ -311,6 +311,7 @@ class TestProcessInstanceProcessor(BaseTest): ProcessInstanceService.complete_form_task(processor, spiff_manual_task, {}, initiator_user, human_task_one) assert process_instance.status == "complete" + # this test has been failing intermittently for some time on windows, perhaps ever since it was first added def test_properly_resets_process_to_given_task_with_call_activity( self, app: Flask, @@ -350,12 +351,14 @@ class TestProcessInstanceProcessor(BaseTest): ProcessInstanceService.complete_form_task(processor, spiff_manual_task, {}, initiator_user, human_task_one) processor.suspend() - task_model_to_reset_to = ( + all_task_models_matching_top_level_subprocess_script = ( TaskModel.query.join(TaskDefinitionModel) .filter(TaskDefinitionModel.bpmn_identifier == "top_level_subprocess_script") .order_by(TaskModel.id.desc()) # type: ignore - .first() + .all() ) + assert len(all_task_models_matching_top_level_subprocess_script) == 1 + task_model_to_reset_to = all_task_models_matching_top_level_subprocess_script[0] assert task_model_to_reset_to is not None ProcessInstanceProcessor.reset_process(process_instance, task_model_to_reset_to.guid) @@ -364,7 +367,7 @@ class TestProcessInstanceProcessor(BaseTest): process_instance = ProcessInstanceModel.query.filter_by(id=process_instance.id).first() processor = ProcessInstanceProcessor(process_instance) - # make sure we reset to the task we expected + # make sure we did actually reset to the task we expected ready_or_waiting_tasks = processor.get_all_ready_or_waiting_tasks() top_level_subprocess_script_spiff_task = next( task for task in ready_or_waiting_tasks if task.task_spec.name == "top_level_subprocess_script" @@ -373,7 +376,11 @@ class TestProcessInstanceProcessor(BaseTest): processor.resume() processor.do_engine_steps(save=True, execution_strategy_name="greedy") + # reload again, just in case, since the assertion where it says there should be 1 active_human_task + # is failing intermittently on windows, so just debugging. + process_instance = ProcessInstanceModel.query.filter_by(id=process_instance.id).first() assert len(process_instance.active_human_tasks) == 1 + human_task_one = process_instance.active_human_tasks[0] spiff_manual_task = processor.bpmn_process_instance.get_task_from_id(UUID(human_task_one.task_id)) ProcessInstanceService.complete_form_task(processor, spiff_manual_task, {}, initiator_user, human_task_one)