From 92d77f3a512f0febe4d6b6b0cf8fc161ca83a9d6 Mon Sep 17 00:00:00 2001 From: jasquat Date: Mon, 21 Nov 2022 14:12:04 -0500 Subject: [PATCH] allow getting all process models, process instances should not save when they are initialized, and fixed some cypress tests w/ burnettk --- .../src/spiffworkflow_backend/__init__.py | 4 +-- .../services/acceptance_test_fixtures.py | 22 ++++++------ .../services/background_processing_service.py | 2 +- .../services/process_instance_processor.py | 13 ------- .../services/process_instance_service.py | 5 --- .../services/process_model_service.py | 24 +++++++------ .../integration/test_process_api.py | 35 +++++++++++++++++++ .../cypress/e2e/process_instances.cy.js | 4 +-- .../cypress/support/commands.js | 2 ++ .../src/routes/ProcessGroupShow.tsx | 1 + .../src/routes/ProcessModelShow.tsx | 31 ++++++++++++++++ 11 files changed, 98 insertions(+), 45 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/__init__.py b/spiffworkflow-backend/src/spiffworkflow_backend/__init__.py index d17beac3c..5d591d847 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/__init__.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/__init__.py @@ -67,9 +67,9 @@ def start_scheduler( seconds=10, ) scheduler.add_job( - BackgroundProcessingService(app).run, + BackgroundProcessingService(app).process_waiting_process_instances, "interval", - seconds=30, + seconds=10, ) scheduler.start() diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/acceptance_test_fixtures.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/acceptance_test_fixtures.py index cfea3148b..dff7be8c6 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/acceptance_test_fixtures.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/acceptance_test_fixtures.py @@ -1,5 +1,4 @@ """Acceptance_test_fixtures.""" -import json import time from flask import current_app @@ -8,13 +7,15 @@ from tests.spiffworkflow_backend.helpers.base_test import BaseTest from spiffworkflow_backend.models.process_instance import ProcessInstanceModel from spiffworkflow_backend.models.process_instance import ProcessInstanceStatus +from spiffworkflow_backend.services.process_instance_service import ( + ProcessInstanceService, +) def load_acceptance_test_fixtures() -> list[ProcessInstanceModel]: """Load_fixtures.""" current_app.logger.debug("load_acceptance_test_fixtures() start") - test_process_group_id = "" - test_process_model_id = "acceptance-tests-group-one/acceptance-tests-model-1" + test_process_model_id = "misc/acceptance-tests-group-one/acceptance-tests-model-1" user = BaseTest.find_or_create_user() statuses = ProcessInstanceStatus.list() current_time = round(time.time()) @@ -28,16 +29,13 @@ def load_acceptance_test_fixtures() -> list[ProcessInstanceModel]: # suspended - 6 hours ago process_instances = [] for i in range(len(statuses)): - process_instance = ProcessInstanceModel( - status=statuses[i], - process_initiator=user, - process_model_identifier=test_process_model_id, - process_group_identifier=test_process_group_id, - updated_at_in_seconds=round(time.time()), - start_in_seconds=current_time - (3600 * i), - end_in_seconds=current_time - (3600 * i - 20), - bpmn_json=json.dumps({"i": i}), + + process_instance = ProcessInstanceService.create_process_instance( + test_process_model_id, user ) + process_instance.status = statuses[i] + process_instance.start_in_seconds = current_time - (3600 * i) + process_instance.end_in_seconds = current_time - (3600 * i - 20) db.session.add(process_instance) process_instances.append(process_instance) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/background_processing_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/background_processing_service.py index 08a2b02df..1771c2c8b 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/background_processing_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/background_processing_service.py @@ -14,7 +14,7 @@ class BackgroundProcessingService: """__init__.""" self.app = app - def run(self) -> None: + def process_waiting_process_instances(self) -> None: """Since this runs in a scheduler, we need to specify the app context as well.""" with self.app.app_context(): ProcessInstanceService.do_waiting() diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py index be32a2f06..668ab15eb 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -359,21 +359,8 @@ class ProcessInstanceProcessor: subprocesses=subprocesses, ) self.bpmn_process_instance.script_engine = self._script_engine - self.add_user_info_to_process_instance(self.bpmn_process_instance) - if self.PROCESS_INSTANCE_ID_KEY not in self.bpmn_process_instance.data: - if not process_instance_model.id: - db.session.add(process_instance_model) - # If the model is new, and has no id, save it, write it into the process_instance model - # and save it again. In this way, the workflow process is always aware of the - # database model to which it is associated, and scripts running within the model - # can then load data as needed. - self.bpmn_process_instance.data[ - ProcessInstanceProcessor.PROCESS_INSTANCE_ID_KEY - ] = process_instance_model.id - self.save() - except MissingSpecError as ke: raise ApiError( error_code="unexpected_process_instance_structure", diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_service.py index 802718018..3c81e1b12 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_service.py @@ -323,14 +323,9 @@ class ProcessInstanceService: """Serialize_flat_with_task_data.""" results = {} try: - original_status = process_instance.status processor = ProcessInstanceProcessor(process_instance) process_instance.data = processor.get_current_data() results = process_instance.serialized_flat - # this process seems to mutate the status of the process_instance which - # can result in different results than expected from process_instance_list, - # so set the status back to the expected value - results["status"] = original_status except ApiError: results = process_instance.serialized return results diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_model_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_model_service.py index 2431289c5..c52426533 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_model_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_model_service.py @@ -2,6 +2,7 @@ import json import os import shutil +from glob import glob from typing import Any from typing import List from typing import Optional @@ -165,17 +166,20 @@ class ProcessModelService(FileSystemService): self, process_group_id: Optional[str] = None ) -> List[ProcessModelInfo]: """Get process models.""" - process_groups = [] - if process_group_id is None: - process_groups = self.get_process_groups() - else: - process_group = self.get_process_group(process_group_id) - if process_group is not None: - process_groups.append(process_group) - process_models = [] - for process_group in process_groups: - process_models.extend(process_group.process_models) + root_path = FileSystemService.root_path() + if process_group_id: + awesome_id = process_group_id.replace("/", os.sep) + root_path = os.path.join(root_path, awesome_id) + process_model_glob = os.path.join(root_path, "**", "process_model.json") + for file in glob(process_model_glob, recursive=True): + process_model_relative_path = os.path.relpath( + file, start=FileSystemService.root_path() + ) + process_model = self.get_process_model_from_relative_path( + os.path.dirname(process_model_relative_path) + ) + process_models.append(process_model) process_models.sort() return process_models diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_process_api.py b/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_process_api.py index fbbf7deb7..77788126d 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_process_api.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_process_api.py @@ -355,6 +355,41 @@ class TestProcessApi(BaseTest): assert response.json["primary_process_id"] == "superduper" assert response.json["is_review"] is False + def test_process_model_list_all( + self, + app: Flask, + client: FlaskClient, + with_db_and_bpmn_file_cleanup: None, + with_super_admin_user: UserModel, + ) -> None: + """Test_process_model_list_all.""" + group_id = "test_group/test_sub_group" + self.create_process_group(client, with_super_admin_user, group_id) + + # add 5 models to the group + for i in range(5): + process_model_identifier = f"{group_id}/test_model_{i}" + model_display_name = f"Test Model {i}" + model_description = f"Test Model {i} Description" + self.create_process_model_with_api( + client, + process_model_id=process_model_identifier, + process_model_display_name=model_display_name, + process_model_description=model_description, + user=with_super_admin_user, + ) + + # get all models + response = client.get( + "/v1.0/process-models?per_page=1000", + headers=self.logged_in_headers(with_super_admin_user), + ) + assert response.json is not None + assert len(response.json["results"]) == 5 + assert response.json["pagination"]["count"] == 5 + assert response.json["pagination"]["total"] == 5 + assert response.json["pagination"]["pages"] == 1 + def test_process_model_list( self, app: Flask, diff --git a/spiffworkflow-frontend/cypress/e2e/process_instances.cy.js b/spiffworkflow-frontend/cypress/e2e/process_instances.cy.js index 09cad2987..34c4e56de 100644 --- a/spiffworkflow-frontend/cypress/e2e/process_instances.cy.js +++ b/spiffworkflow-frontend/cypress/e2e/process_instances.cy.js @@ -53,9 +53,9 @@ const updateBpmnPythonScriptWithMonaco = ( cy.get('.monaco-editor textarea:first') .click() .focused() // change subject to currently focused element - // .type('{ctrl}a') // had been doing it this way, but it turns out to be flaky relative to clear() .clear() - .type(pythonScript, { delay: 30 }); + // long delay to ensure cypress isn't competing with monaco auto complete stuff + .type(pythonScript, { delay: 120 }); cy.contains('Close').click(); // wait for a little bit for the xml to get set before saving diff --git a/spiffworkflow-frontend/cypress/support/commands.js b/spiffworkflow-frontend/cypress/support/commands.js index 40074518d..1ec6a8aec 100644 --- a/spiffworkflow-frontend/cypress/support/commands.js +++ b/spiffworkflow-frontend/cypress/support/commands.js @@ -93,6 +93,8 @@ Cypress.Commands.add( 'navigateToProcessModel', (groupDisplayName, modelDisplayName, modelIdentifier) => { cy.navigateToAdmin(); + cy.contains('Misc').click(); + cy.contains(`Process Group: Misc`); cy.contains(groupDisplayName).click(); cy.contains(`Process Group: ${groupDisplayName}`); // https://stackoverflow.com/q/51254946/6090676 diff --git a/spiffworkflow-frontend/src/routes/ProcessGroupShow.tsx b/spiffworkflow-frontend/src/routes/ProcessGroupShow.tsx index 3d6a0ee4f..f8c856e1a 100644 --- a/spiffworkflow-frontend/src/routes/ProcessGroupShow.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessGroupShow.tsx @@ -111,6 +111,7 @@ export default function ProcessGroupShow() { ]} />

Process Group: {processGroup.display_name}

+

{processGroup.description}